JVM内存布局
总体内存概念布局
-
线程私有数据
-
虚拟机栈
记录Java方法调用顺序,每调用一个方法,就会向栈中压入一个栈帧,栈帧中记录着局部变量表、操作数栈、动态链接、方法出口等信息
-
本地方法栈
记录native方法调用顺序,每调用一个Native方法,就会向栈中压入一个栈帧,栈帧中记录着局部变量表、操作数栈、动态链接、方法出口等信息
-
程序计数器
记录当前线程字节码指令执行的行号
-
-
线程共享数据
-
堆
存储所有的类实例和数组,是JVM中占用内存最多的区域,垃圾回收主要也是在这个区域
-
方法区
存储Java的类元数据和运行时常量池,包括所有的类信息、常量、类变量、动态编译缓存等
-

虚拟机栈
虚拟机栈就是一个非常关键的部分,看名字就知道它是一个栈结构,每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧(其实就是栈里面的一个元素),栈帧中包括了当前方法的一些信息,比如局部变量表、操作数栈、动态链接、方法出口等。

本地方法栈
与虚拟机栈结构类似
堆
堆结构在JDK1.8前后有改变,JDK1.8前堆中的永久代是方法区的实现,之后方法区使用元空间实现,不在堆内存中,使用直接内存不属于JVM内存
堆内存被划分三部分新生代、老年代、永久代;JDK1.8及之后为两部分,只有新生代和老年代,永久代被元空间取代
元空间在直接内存中,不属于JVM的内存
在HotSpot虚拟机中,新生代被划分为三块,一块较大的Eden空间和两块较小的Survivor空间,默认比例为8:1:1,老年代的GC评率相对较低,永久代一般存放类信息等(其实就是方法区的实现)
所有新创建的对象,在一开始都会进入到新生代的Eden区(如果是大对象会被直接丢进老年代)
在一次垃圾回收之后,Eden区域没有被回收的对象,会进入到Survivor区。在一开始From和To都是空的,而GC之后,所有Eden区域存活的对象都会直接被放入到From区,最后From和To会发生一次交换,也就是说目前存放我们对象的From区,变为To区,而To区变为From区
在Eden区的存活对象复制到From区之后,所有To区域中的对象会进行年龄判定(每经历一轮GC年龄+1,如果对象的年龄大于默认值为15,那么会直接进入到老年代,否则移动到From区)
垃圾收集分为:
- Minor GC - 次要垃圾回收,主要进行新生代区域的垃圾收集。
- 触发条件:新生代的Eden区容量已满时。
- Major GC - 主要垃圾回收,主要进行老年代的垃圾收集。
- Full GC - 完全垃圾回收,对整个Java堆内存和方法区进行垃圾回收。
- 触发条件1:每次晋升到老年代的对象平均大小大于老年代剩余空间
- 触发条件2:Minor GC后存活的对象超过了老年代剩余空间
- 触发条件3:永久代内存不足(JDK8之前)
- 触发条件4:手动调用
System.gc()方法
JDK1.8前

JDK1.8

方法区
方法区也是整个Java应用程序共享的区域,它用于存储所有的类信息、常量、静态变量、动态编译缓存等数据,可以大致分为两个部分,一个是类信息表,一个是运行时常量池。

完整JVM内存布局
JDK1.8前

JDK1.8
