文章目录
- Heap堆结构简介
- heap堆new对象流程
- Transfervalue
- 对象生命周期和GC
- 永久代
- 堆参数调优
- GC收集日志信息
Heap堆结构简介
堆包括三部分:新生代,老年代,元空间/永久代。
新生代包括:伊甸园区,幸存者0区,幸存者1区。
7是永久代,8是元空间。
物理上有2部分:新生+养老。
heap堆new对象流程
知识点:new一个对象,是new在了伊甸园区。
伊甸园区发生的GC是YGC。y是young的意思。也是轻量级的GC。YGC之后幸存的对象,放到幸存者0区,别名from区。
如果15次GC都没被清空,就会送到养老区。养老区满了,开启Full GC(FGC),Full gc 多次执行完毕之后,还不能清理出空间,就OOM了。
Transfervalue
基本类型传复印件,引用类型传引用,string特殊,方法内部会新建一个指向,并不改变原来的指向。
这个题需要注意:栈里面压入一个一个的方法(栈帧),每一个栈帧里面有不同的局部变量,age就是局部变量。虽然传给了另一个方法,是另一个栈帧的入参,是另外一个部分的局部变量,在那个栈帧中改变age,不影响main这个栈帧中age的值。
new person,引用在栈,数据在堆中,传给方法的是内存地址,指向关系如下图:
元空间里有常量池,string的使用原则是池子里有我就复用,没有我就在常量池里面新建。string传过去的确实是引用,但是他新建的逻辑是没有就新建,而不是在原来位置修改,就导致了,main中的string指向的内容没有改变。
对象生命周期和GC
幸存者0区,简称s0,别名叫from区,幸存者1区,简称s1,别名叫to区。
重点:注意关注堆中各部分的比例。新生代:老年代 = 1:2 ,Eden:From:to = 8:1:1.
轻GC(ygc,minorGC)的过程:复制,清空,互换。
永久代
永久代是7的叫法,元空间是8的叫法。
永久代几乎没有垃圾回收。
堆参数调优
这张图代表的是各个区发生的GC类型,以及调整时的参数设置。
逻辑上JVM分为三块,物理上分为2块。
理解每个参数的意思:
- Xms:s是start的意思,初始化大小
- Xmx:x是max的意思,最大化大小
- Xmn:n是new的意思,代表新生代三块组合起来的大小
新生区跟养老区是默认1:2的关系。 - XX:PermSize,永久代的初始值
- XX:MaxPermSize,永久代的最大值
跟永久代有关的是jdk7的用法,以后用不到了,jdk8以后就改名了。
jdk8只是更新了一个元空间,替代了持久区,其他是一样的。
因为这些参数设置的问题,你的内存条可能不会被全部使用,也就是说,单纯差个内存条,不会让程序性能有想象中的提升,需要调整jvm参数去适配。默认java出厂只用物理内存的四分之一,加个4G内存条,只用1G。
查看CPU核数:
Runtime这个类就是对JVM体系结构中运行时数据区的抽象。
代码测试:Xms(64分之一内存条),Xmx(四分之一内存条)的设置的值。
运行结果:
最佳实践:生产环境,Xms和Xmx的大小必须一样!!!!是为了避免jvm和应用程序争抢内存,避免内存忽高忽低,产生停顿。
idea如何配置jvm?
上图是演示变更JVM的堆内存的初始值和最大值,然后打印gc的日志。
配置之后再次运行上面的4行代码,结果如下:
分析上图,实现了初始和最大堆空间一致的效果。根据GC日志,可以证明,堆由young区,old区,metaspace区组成。这是逻辑组成的证明。也可以证明物理组成,因为young区的total|+old区的total就等于我们配置的Xmx和Xms。如此就证明了物理上由young+old组成。如下图:
如何干爆堆,测试方式i如下,思路为调整堆大小,然后死循环创建对象。
运行实际结果截图:堆空间溢出
5个常见的异常,这个需要回答。
一句话撑爆:
回到循环创建的代码,分析打印的日志:
可以分析出先young-gc,很多次ygc之后是一次full-gc,然后又是多次young gc。直到一瞬间,full gc之后也没用空间了,jvm就撂挑子了,如下图:
最初的gc过程有这个过程的理论描述(下图),上图是实际的执行过程。发生堆内存的oom异常,最近一次gc是full gc。
GC收集日志信息
GC的执行过程一定是先轻后重,先轻gc(young gc,minor gc)再重GC(major gc)。
分析一下gc的日志:
第一行,因为分配空间失败了,产生young gc。也就是内存不够用才gc。
第二行:gc发生在young区域,2048是gc之前的用的空间,488是gc之后用的空间,2560是young区(新生代)的总内存(总共大小)。young gc前jvm堆内存占用2048k,之后是773k,9728k是配置的jvm堆总大小。 整个ygc耗时0.0015243 秒。
第三行:时间,用户耗时,系统耗时,时间耗时。
分析一下爆炸之前的最后一个full-gc:
full gc的结果只有2个,要么成功,要么就oom。
young区总计2048k,gc前后都是0,old区gc前后只改变了很少的一点,元空间也是,几乎没有清理出太多空间。
清理不出来空间,时间就是0,这种情况,就崩了,会导致oom。