JVM内存模型

1、类的加载、连接和初始化

      加载:查找并加载类的二进制数据(字节码文件)

      连接:

             验证:确保被加载的类的正确性(手工生成class文件,可

                        能不符合JVM标准规范)

             准备:为类的静态变量分配内存,并将其初始化为默认值

                     (这个时候并不涉及new对象的操作)

             解析:把类中的符号引用转换为直接引用(Child.run()转

                        换为pointer)

      初始化:为类的静态变量赋予正确的初始值(正确:用户赋予的

                    值)

      示例:MyTest

   1.1类的使用方式:

        所有的类或接口只有在java程序“首次主动使用”才会初始化

        主动使用:

               (1)创建类的实例new Test();

               (2)访问某个类的静态变量,或者为某个类的静态变量赋值:a =

                    Test.b; Test.b = a;

               (3)调用类的静态方法:Test.doSomething();

               (4)初始化一个类的子类:

                    class Parent{};class Childextends Parent{

                    public static int a= 3};

                    Child.a =4;

              (5) java虚拟机就启动时被标明为启动类的类(java TestTest

                   中有main方法)

              (6)反射Class.forName(“Test”);

         除此之外的使用都是被动使用,被动使用是不会触发初始化的。

   1.2类的加载:

        将.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,又 来封装在方法区内的数据结构,class对象是jvm在类加载时自动创建的。

  1.3类加载器

        Java虚拟机自带的类加载器:

       根类加载器(Bootstrap)(c++ java代码中无法获取该类)

       扩展类加载器(Extension)(java )

       系统类加载器(System)(也叫应用加载器)

       用户自定义的类加载器

   层次关系:


       根类加载器:用c++实现,并没有集成java.lang.ClassLoader类

       扩展类记载器:父类加载器为根类加载器,加载目录jre\lib\ext,如果把用户创建的jar包放在这个目录下,则会有扩展类加载器                                  进行加载。

       系统类加载器:父类加载器为扩展类加载器,从环境变量classpath或系统属性java.class.path所指定的目录加载类,是自定义                                   加载类的默认父类加载器。

      (1)核心类库由bootstrap加载器进行加载,获取到为空,其他都可获取,例Test2

      (2)调用一个类的静态变量,且这个静态变量在编译时期就可以确定,则不会进行类的初始化,当这个类在执行阶段才能确                     定,则会进行初始化,例Test4,Test3

      (3)加载顺序—启动类—父类—子类,例Test5,Test6

      (4)调用loadClass方法加载一个类,并不是对类的主动使用,并不会初始化该类。例Test7

  1.4类的加载机制—父委托机制

      (1)除了java自带的根类加载器,其余类加载器都有且仅有一个父类加载器,只有当父类加载器不能进行加载的时候,才会由                子类加载器进行加载。

      (2)父子加载器并非继承关系,子加载器并不一定继承父类加载器

      (3)安全考虑,每个类都会有确定的层次中的一个类加载器进行加载,自定义除外。

     (4)每个类都有自己的命名空间,命名空间由该类加载器及所有父类加载器所加载的类组成。同一个命名空间中,不会存在两                个完整名字相同的类,不同命名空间中,可能存在完整名字相同的类。

  1.5 用户自定义类加载器

        继承ClassLoader类,覆盖findClass方法,会由loadClass方法调用。

   1.6 JVM虚拟机执行整体顺序


2、JVM的内存结构


方法区和对是所有线程共享的内存区域;而java栈、本地方法栈和程序员计数器是运行是线程私有的内存区域。

程序计数器:当前线程所执行字节码指令的行号指示器,线程私有,执行java方法,计数器记录的是java代码的行号,执行native方法则为null(undefined);

虚拟机栈:线程私有,表示java方法执行的内存模型,每个栈帧对应的是一个调用的方法,包括局部变量表、动态链接、操作数栈、指向当前方法所属的类的运行时常量池、方法返回地址和附加信息。


栈帧是保存在虚拟机栈中的,栈帧是用来存储数据和存储部分过程结果的数据结构,同时也被用来处理动态链接(Dynamic Linking)、方法返回值和异常分派(Dispatch Exception)。线程运行过程中,只有一个栈帧是处于活跃状态,称为“当前活跃栈帧”,当前活动栈帧始终是虚拟机栈的栈顶元素。


局部变量表:方法参数,方法内部定义的变量。

操作数栈:每一个方法的调用,都会建立一个操作数栈

动态链接:与静态解析对应,一部分的符号引用会在运行是转化为直接引用

方法返回地址:正常完成出口,异常完成出口

本地方法栈:线程私有,与虚拟机栈类似,为native方法服务

堆:线程共享,存储对象本身及数组

方法区:线程共享,类信息,静态变量,常量,编译后的代码等

运行时常量池:存放编译期生成的各种字面量和符号引用

2.1对象的创建—内存分配

(1)jvm遇到一个new指令,检查这个指令的参数是否能在常量池中定位到一个类的符号引用,然后检查这个类代表的类是否已被加载、解析和初始化。如果没有,则进行类加载。

(2)类的加载—先加载父类,先加载静态块,顺序加载。

(3)JVM开始为对象分配内存,两种方式:

指针碰撞:java堆内存规整,GC带有压缩整理功能

空闲列表:java堆内存空间并不规整。

解决多线程分配内存的问题:

失败重试:保证更新操作的原子性

本地线程缓存取:TLAB,在启动线程时,就会在堆中给该线程预留一个内存空间

(4)内存分配完后,首先内存空间都初始化为零值。若使用TLAB,则在分配TLAB时即已初始化成功。

(5)设置对象头(Object Header):如何才能找到类的元数据信息,对象的哈希码,对象的GC分代年龄等信息。

(6)执行方法,将对象初始化为指定的值。

3、GC垃圾回收

3.1判断对象失效

(1)引用计数算法

给对象添加一个引用计数器,每当有一个地方引用它,计数器值就加1,当引用失效就减1,计数器为0的对象就是不可能再被引用的对象。

实现简单,但无法解决循环引用的问题

(2)可达性分析算法

通过一系列成为“GC ROOT”的对象作为起始点,向下搜索,走过的路径成为引用链,当一个对象到GC ROOT没有任何引用链相连时,则证明此对象是不可用的。

可作为GC ROOT的对象有:

虚拟机栈中引用的对象

方法区中静态属性引用的对象

方法区中常量引用的对象

本地方法栈中JNI(native方法)引用的对象


3.2垃圾回收算法

(1)标记—清除算法

先对不用的对象进行标记,然后清除


(2)复制算法

将内存按容量分为几块,在一个时间段只使用一块内存,当这块内存用完,则将内存清理干净,然后将可用的对象复制到另一个区域。



(3)标记—整理算法

复制算法在对象存活率较高时要进行较多的复制操作,效率将变低,而且浪费空间。

标记—整理的标记过程与标记—清除一样,但后续步骤不是对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。


(4)分代收集算法

根据对象存活周期的不同将内存划分为几块,一般把java堆分为新生代和老年代。

在新生代中每次垃圾收集时都发现有大批对象死去,只有少量存活,就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代因为对象存活率搞,没有额外空间对它进行分配担保,就必须使用标记—清理或标记—整理算法来进行回收

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容