虚拟机运行时的数据区
对于这五个区域我大概做一个大概介绍:
程序计数器(program counter register):线程私有,一块较小的内存空间,可以看作当前线程所执行的字节码的行号指示器。由于java虚拟机是采用多线程,通过线程切换获得时间片得到cpu的控制权。为了线程切换后能恢复到正确的执行位置。
虚拟机栈: 线程私有,生命周期与线程相同,虚拟机栈描述的是Java方法执行的内存模型,每个方法在执行时会形成一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,一个方法从调用到执行完毕,就是一个栈帧从进栈到出栈的过程。通过 -Xss控制大小,如果线程请求的栈深度大于虚拟机所允许的深度,会抛出StatckOverflowError。通过递归死锁会引发这种问题。
本地方法栈: 线程私有,作用于Java虚拟机栈类似,只不过Java虚拟机栈执行Java方法,而本地方法栈运行本地的Native方法。
堆(heap),所有线程共享,Java虚拟机管理的最大的一块内存区域,用于存放对象实例。也就是说对象的出生和回收都是在这个区域进行的。堆分为初生代(Young Gen)和老年代(Tenured Gen),比例默认为1:2,而初生代又分为Eden和From和To三个区域,比例默认为8:1:1,通过-Xmx和-Xms控制大小,如果内存不足会抛OutOfMemoryError。通过GC释放
方法区:线程共享,用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。在1.7及之前方法区是由永久代实现的(HotSpot虚拟机),1.8开始由元空间(MetaDataSpace)实现。
Young GC
Eden Space 满了 ;Survivor Space 满了Full GC
老年代满了;持久代满了1
jstat –gcutil 进程ID 刷新时间(可以实时监控jvm 的gc情况)
JDK1.7和JDK1.8的内存结构比较
JDK1.7内存结构
方法区: 也叫持久代,通过-XXMaxPerSize控制大小,当方法区无法满足内存分配需求时也会抛出OutOfMemoryError。特别注意动态代理子类,在运行期会创建很多新的子类,导致空间不足。
运行时常量池:在JDK1.7中,是运行时常量池是方法区的一部分,用于存放编译期生成的各种字符变量和符号引用。其实除了运行时常量池,还有字符串常量池,class常量池
JDK1.8内存结构
JDK1.8与1.7最大的区别是1.8将永久代取消,取而代之的是元空间,在1.8中方法区是由元空间来实现,所以原来属于方法区的运行时常量池就属于元空间了。
元空间属于本地内存,所以元空间的大小仅受本地内存限制,但是可以通过-XX:MaxMetaspaceSize进行增长上限的最大值设置,默认值为4G,元空间的初始空间大小可以通过-XX:MetaspaceSize进行设置,默认值为20.8M,还有一些其他参数可以进行设置,元空间大小会自动进行调整.
对象分配规则:
对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。
大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。
长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,直到达到阀值对象进入老年区。
动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。
空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC。
这里要说明一下,要区分字符串常量池和运行时常量池:
- 在JDK1.7之前运行时常量池逻辑包含字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代
- 在JDK1.7字符串常量池被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代
- 在JDK1.8 hotspot移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)
jdk1.8 默认GC
- 默认使用ParallelGC收集器,也就是在新生代使用Parallel Scavenge收集器,老年代使用ParallelOld收集器