JVM

JVM结构

总体上JVM由类装载子系统、运行时数据区、执行引擎和内存回收系统组成。其中我们最关心的是运行时数据区,即JVM内存部分,由直接内存、方法区、Java堆、Java虚拟机栈、本地方法栈、程序计数器组成。


JVM_第1张图片
JVM结构示意图

1.1 运行时数据区
方法区
存储已加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
Java堆
JVM管理的内存中最大的一块,存储对象实例和数组。内部会分为线程私有的分配缓冲区。物理上不必连续,但逻辑上必须连续。是GC重点回收区域。
方法区
存储已加载的类信息、常量、静态变量、即时编译器编译的Java代码。
直接内存
不受JVM管理。避免在Java堆和Native堆中来回复制数据,在一些场景中显著提高性能。
Java虚拟机栈
是Java执行方法的内存模型。每个方法被执行的时候会创建一个栈桢,方法的执行过程就是栈桢入栈和出栈的过程。栈桢中保存了局部变量表(方法执行过程中的所有变量)、动态链接(栈桢在运行时常量池中的引用)、操作数栈(操作变量的内存模型)、方法出口(返回值)。
本地方法栈
与虚拟机栈不同的是,虚拟机栈为虚拟机执行Java方法服务,本地方法栈为虚拟机使用到的本地方法服务。
程序计数器
指向当前线程正在执行的Java字节码指令。
1.2 堆内存的划分
Java堆的内存划分为新生代Eden,老年代Old Menory,永久代Perm。JDK8中Perm被取消,用MetaSpace代替,存放在本地内存中,是对JVM中方法区的实现。


JVM_第2张图片
堆内存的划分

垃圾回收机制

  1. GC判断策略
    1.1 引用计数法
    堆中的每个对象都会有一个引用计数。当一个对象被创建的时候,就被分配给一个变量,该变量的计数设置为1。当任何其他变量被设置为这个对象的引用时,计数加1。当引用这个对象的任何变量超过生命周期或者设置为新值时,计数减1。当计数为0时,对象实例可以当作垃圾收集。
    优点:引用计数收集器可以很快的执行,交织在程序运行中。对程序需要不被长时间打断的实时运行环境有利。
    缺点:不能检测出循环引用,当对象存在循环引用时,对象永远不会被回收。
    1.2 可达性分析 GC Root
    从GC Root开始向下查找引用节点,当一个节点不存在任何引用链时,将被判定为无用的对象。
    可以作为GC Root的对象包括以下几种:
    a. 方法区中的静态变量引用对象
    b. 方法区中的常量引用对象
    c. 虚拟机栈中引用的对象(栈桢中的局部变量表)
    d. 本地方法栈中的JNI(Native方法)引用
    1.3 Java中的引用
    强引用:
    在程序中普遍存在,类似Object obj = new Object()这类引用,只要强引用存在,对象永远不会被回收。
    软引用:
    描述一些有用但是非必需的对象。在系统将要发生内存溢出异常之前,会将这些对象纳入回收范围,并进行二次回收。如果回收了这些对象仍然没有足够的内存,则会抛出异常。
    弱引用:
    描述非必需对象,强度比软引用更弱。这些对象只能存活到下一次GC之前。当发生GC的时候,无论内存够不够用,都会回收这些对象。
    虚引用:
    最弱的一种引用关系。虚引用的存在完全不会对生存时间造成影响,也不能通过虚引用获得任何实例。它的作用是在对象被回收时收到一个系统通知。
    1.4 对象死亡(被回收)前的最后阶段
    对象被纳入回收范围,但不一定是“非死不可”的,在回收前还会进行最后一次检查。
    第一次标记:可达性分析后对象不存在任何引用,将进行第一次标记;
    第二次标记:检查对象是否有必要进行 finalize(),在 finalize()中如果没有重新建立链接,则将进行第二次标记。
    两次标记后将进行回收。
    1.5 方法区如何判断是否需要回收
    方法区的回收内容有:废弃常量和无用的类。对于废弃常量,可以直接通过可达性分析来判定,无用的类还要满足三个条件:

该类的所有实例都被回收,即在Java堆中没有该类的实例;
加载该类的 ClassLoader被回收;
该类对应的Java.lang.class在任何地方没有被引用,即在任何地方不能通过反射访问该类

  1. 常用的垃圾回收算法
    2.1 标记清除算法
    通过可达性分析标记无用的对象,然后进行回收。
    优点:速度快,不需要对对象进行移动。
    缺点:会造成内存碎片,导致频繁的垃圾回收。
    2.2 复制算法
    将内存分为多个区,每次GC的时候将存活的对象复制到空闲区,然后清除该区,
    优点:不会造成内存碎片
    缺点:浪费内存空间
    2.3 标记整理算法
    对对象进行标记后,清除无用的对象,将存活的对象移动到内存的一端。
    优点:不会造成内存碎片
    缺点:效率较低
    2.4 分代回收算法
    将内存分为新生代和老年代两个区,堆之外还有一个永久代,新生代每次GC只有少量的对象存活,老年代每次GC只有少量的对象死去。根据每个区不同的特点采用不同的垃圾回收算法。
    新生代垃圾回收算法:
    采用复制-清除算法,因为新生代中每次GC都要回收大部分对象,只有小部分能够存活下来。新生代被分为一个较大的Eden区和两个较小的Survivor(S0,S1)区,默认比例为8:1:1。每次使用Eden区和一个Survivor区,将存活下来的对象复制到未使用的Survivor区,并清除Eden区和已使用的Survivor区。当Survivor满了以后将存活的对象移到老年代。当老年代也满了的时候,出发full GC。
    新生代发生的GC也叫Minor GC,不一定等Eden区满了才触发。
    老年代垃圾回收算法:
    采用标记-整理算法,因为老年代每次GC只会回收少量对象。

  2. GC是什么时候触发的?
    由于对象进行了分代处理,所以GC发生的区域和时间是不一样的。GC有两种类型:young GC和full GC
    3.1 young GC

  3. 类加载器

你可能感兴趣的:(JVM)