【大厂必考之JVM】02,作为Java开发程序员
作者:互联网
总结
《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
===================================================================
- 新生区:新生区分为三部分,一块较大的Eden(伊甸)空间和两块较小的Survivor(幸存者)空间,默认比例为8:1:1。
- 养老区
- 永久存储区/元空间:JDK1.8之后元空间替代永久区
新生区和养老区是垃圾回收的主要区域。新生区和养老区的面积比是1:2
逻辑结构
物理结构
1.1新生区
新生成的对象全部优先存放在新生区中,新生区对象朝生夕死,存活率很低,在新生代中,常规应用进行一次垃圾收集一般可以回收70% ~ 95% 的空间,回收效率很高。
1.2 养老区
在新生代中经历了多次(具体看虚拟机配置的阀值)GC后仍然存活下来的对象会进入老年代中。养老区的空间满了之后会进行Full GC,也叫重GC,FGC。老年代中的对象生命周期较长,存活率比较高,在老年代中进行GC的频率相对而言较低,而且回收的速度也比较慢。当FGC之后,养老区依然没有足够的空间,堆内存溢出。OOM:
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
1.3堆结构的代码验证
首先 idea 进入 Edit configuration -> VM options:
添加:-XX:+PrintGCDetails
/**
-
@Author: 一条IT
-
@Date: 2020/12/6 12:47
*/
public class TestJVM {
public static void main(String[] args) {
// jvm分配的最大内存 默认物理内存的1/4
System.out.println("-Xmx:"+Runtime.getRuntime().maxMemory()/1024/1024+“Mb”);
// jvm分配的初始内存 默认物理内存的1/64
System.out.println("-Mms:"+Runtime.getRuntime().totalMemory()/1024/1024+“Mb”);
}
}
输出结果
-Xmx:1787Mb
-Mms:121Mb
Heap
PSYoungGen total 37888K, used 4592K [0x00000000d6200000, 0x00000000d8c00000, 0x0000000100000000)
eden space 32768K, 14% used [0x00000000d6200000,0x00000000d667c370,0x00000000d8200000)
from space 5120K, 0% used [0x00000000d8700000,0x00000000d8700000,0x00000000d8c00000)
to space 5120K, 0% used [0x00000000d8200000,0x00000000d8200000,0x00000000d8700000)
ParOldGen total 86016K, used 0K [0x0000000082600000, 0x0000000087a00000, 0x00000000d6200000)
object space 86016K, 0% used [0x0000000082600000,0x0000000082600000,0x0000000087a00000)
Metaspace used 3226K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 351K, capacity 388K, committed 512K, reserved 1048576K
可以看到-Mns:初始化分配的内存大小121mb,新生代37888k,老年代86016k,相加约等于121*1024k。证明元空间在物理结构上不属于堆。
以上分配的大小和各自的比例,都可以调整,在JVM调优讲。
二、对象的生命周期和垃圾回收
==============
总结:复制——清空——交换
新生成的对象在Eden区分配(大对象除外,大对象直接进入老年区),当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC也叫轻GC,YGC。
GC进行时,Eden区中所有存活的对象都会被复制到To Survivor区,而在From Survivor区中仍存活的对象会根据它们的年龄值决定去向,年龄值达到年龄阀值(默认为15,新生代中的对象每熬过一轮垃圾回收,年龄值就加1,GC分代年龄存储在对象的header中)的对象会被移到老年区中,没有达到阀值的对象会被复制到To Survivor区。
接着清空Eden区和From Survivor区,新生代中存活的对象都在To Survivor区。接着, From Survivor区和To Survivor区会交换它们的角色,这样新的To Survivor区就又是空的,来承接下一次的轻GC。
交换:from区和to区并不是固定的,而是随时在交换身份,谁是空的是作为to区
当To Survivor区没有足够的空间存放上一次新生代收集下来的存活对象时,需要依赖老年代进行分配担保,将这些对象存放在老年代中。
永久代其实是方法区的一个实现,jdk1.8之后。永久代改为元空间。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,可以指定元空间的大小。
标签:02,used,Java,Survivor,space,对象,必考,GC,空间 来源: https://blog.csdn.net/m0_64867802/article/details/121903721