JVM内存结构 - 运行时数据区
- 共享:方法区和堆是所有线程共享的内存区域
- 私有:Java栈、本地方法栈和程序计数器是线程私有的内存区域
- 方法区/永久代:存储运行时常量池,已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。JDK8以后,方法区被取消了,由元空间取代,功能上区别不大,最大的区别是“元空间”使用操作系统的直接内存,而方法区使用的是虚拟机内存。
- 堆:储存对象实例和数组
- Java栈(Java方法执行的内存模型):每个线程都有自己的java虚拟机栈,线程里的每个方法就是一个栈帧,栈帧又有变量。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机中从入栈到出栈的过程
- 本地方法栈:JVM调用本地方法,为虚拟机能使用到Native方法服务
- 程序计数器:记录当前线程所执行到的字节码行号
JVM内存结构 - Java Memory Model
- 堆内存:堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分为三部分,Eden空间、From Survivor空间、To Survivor空间,默认情况下年轻代按照8:1:1的比例分配
- 方法区:方法区储存类信息、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆)
- 栈:栈又分为Java虚拟机栈和本地方法栈,主要用于方法的执行
JVM 内存结构 - 对象分配规则
GC类型
- Minor GC针对新生代的GC
- Major GC 针对老年代的GC
- Full GC 针对新生代、老年代和永久代的GC
对象分配规则
- 对象优先分配在Eden区
- 大对象直接进入老年代(大对象是指需要大量连续空间的对象)
- 长期存活的对象进入老年代:虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,直到达到阀值(默认阈值 15)对象进入老年代
- 动态判断对象的年龄:如果Survivor区中相同年龄的对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄对象可以直接进入老年代
- 空间分配担保:只有老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行Full GC