- JVM结构剖析
- JVM中创建对象的过程
- 方法的定位
- 垃圾回收算法
- 堆的继续切分
- 垃圾清除算法
- 垃圾回收机制
分类如下:
- 方法区:
创建对象后,主要存放静态变量、类信息、常量、即时编译的代码等
- 堆:
对象实例和数组
- 虚拟机栈:
作为一个栈帧存放该方法中的,局部变量表、动态链接、操作数栈、方法出口
- 本地方法栈:
本地方法JNI
- 程序计数器:
JVM中创建对象的过程记录运行至编译后的汇编指令的位置
- 首先,对象创建时,会经历加载、链接、初始化的过程。
- 加载:
加载的过程需要完成以下3件事情:
1:通过一个类的全限定名来获取此类的二进制字节流
2:将这个字节流所代表的静态存储结构方法区的运行时的数据接口
3:在内存中生成一个代表这个类的Class对象,作为方法区这个类的数据访问入口
数组加载是不经过类加载器的,由JVM直接创建。但其数组类的元素类型最终是靠类加载器去创建的。
加载阶段完成后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区中。- 链接:验证、准备、解析三个阶段
- 验证:
验证的目的为了确保该信息是否符合当前虚拟机的要求,不危害虚拟机的安全。否则抛出一个VerityError的错误。
验证分为:
1:文件格式验证
2:元数据验证
3:字节码验证
4:符号引用验证
- 准备:
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在这些方法区中进行分配。
- 解析:
在解析阶段,虚拟机会把常量池内的符号引用替换为直接引用。解析动作主动针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符。
- 初始化:
方法的定位类初始化是类加载过程的最后一个步骤,到了该阶段,才真正开始执行类中定义的Java程序代码。
也就是我们的初始化就是执行init方法的过程。
我们经常会遇到对象是否可以被GC时,谈论两种方法,分别是:引用计数法和Root引用可达法
- 而我们的对象在访问定位时,主要通过:
- 通过句柄访问:
通过句柄访问其实就是在堆中创建一个句柄池,该句柄池存放到对象实例数据和对象类型数据的指针。
而引用的是Java栈本地变量表中存放的变量去引用。- 直接访问:
也就是该变量(存放在Java栈中的变量)直接指向堆中的对象实例数据,该实例数据同样存放着对象类型数据(存放在方法区上)。
-
接上面的该对象是否可以存活,也就是引用计数法和可达性分析:
- 引用计数法:
给对象添加一个引用计数器,没被引用一次就将其加一,解除引用则减去一。
- 可达性分析法:
将Root对象作为初始点,将这些出发点到最终的验证对象所经过的路径命名为引用链。当一个对象到GC Roots没有任何引用链相连时,则表示不可用。标记两次都命中的数据才能作为可达数据
可作为GC Roots的对象是:
1:虚拟机栈中的引用对象
2:方法区中静态属性引用对象
3:方法区中常量引用的对象
4:本地方法栈中JNI引用的对象 -
而我们的对象‘引用’一般有以下四种:
- 强引用:一般创建对象时的引用
Object obj = new Object();
- 软引用:使用SoftReference类实现的软引用,一般在垃圾回收时进行回收
- 弱引用:使用WeakReference类实现的引用,存活不过下一次垃圾回收之前。
- 虚引用:PhantomReference类实现的,一般作为该对象被垃圾回收器回收时收到的一个系统通知。
新生区:
一般Eden区和两个Survivor区比例为8:1:1
- Eden区
对象第一次放入的区域,很多的数据只会在该区域存活一次,即被清除
- 两个Survivor区
Eden区存活下来的数据会被放入to区,而from区是存放上一个垃圾回收时存活下来的数据。to和from区是不断交替变换的,只有存活次数大于15次或在担保策略下存活的数据大于新生区的10%的大小时,其余数据都会进入老年区
- 老年区:
垃圾清除算法大内存的数据、担保策略进入的数据和存活代数大于15的数据都会进入,该区域的GC频率较低,每次GC都是一次full GC,会将整个虚拟机暂停,一切活动都会停止,而我们的内存分配需要让该GC尽量少的出现。
- 复制算法
就是新生代中的两个Survivor区就是进行的复制算法。
- 标记-清除算法
将存活下来的数据标记,然后将未标记的对象清除(会产生垃圾碎片)
- 标记-整理算法
将存活下来的对象标记,其余清除,然后将存活的数据整理至连续地址区域,确保垃圾碎片不存在(很耗费时间)
- 分代算法
垃圾回收机制也就是上面所说的新生代和老年代的区分就是为了实现该分代算法。
以上都是垃圾算法的思路,真正落地的算法又分为:
- Serial收集器:
单线程收集器,也就是在新生代和老年代都是使用单GC线程来进行清除,只是新生代为复制算法,老年代为标记整理算法。
- ParNew算法:
是Serial收集器的多线程版本
在新生代的GC中使用多线程进行清除,算法都是使用复制算法
- Serial Old:Serial收集器的老年代版本
- Parallel Old收集器:
新生代和老年代都是多线程进行清除
- CMS收集器:
该收集器分为以下几个过程:
1:初始标记:标记GC Roots能直接关联到的对象
2:并发标记:进行GC Roots Tracing
3:重新标记:修正并发标记期间的变动部分
4:并发清理
- G1收集器:
现如今使用比较多的一中垃圾回收机制
也分为以下几个回收步骤:
1:初始标记
2:并发标记
3:最终标记
4:筛选回收(多线程)



