性能测试连载 (21)-jvm 内存空间与 gc 机制
https://pan.baidu.com/s/1df1HDkFzChYNAbsSazizpw 提取码:hhn7
jmeter 全系列文档资料
https://pan.baidu.com/s/1rD3H9EGbu0u11E8ofpAl3A 提取码:8q65
性能测试初级到高级系列资料
jvm 内存空间分析
JVM 内存包括区域
Heap(堆区)
New Generation(年轻代)
Eden 伊甸园
Survivor From
Survivor To
Old Generation(老年代)
方法区
Permanent Generation(持久代)
Stack(栈区)
Metaspace(元空间)
Direct ByteBuffer(堆外内存)
GC 机制
年轻代 (young 区)
伊甸园
年轻代的内存区域分为:一个 Eden 区和两个 Survivor 区。对象被创建时,首先创建在年轻代eden 区(如果年轻代空间不足,对象直接分配在老年代上)。
Eden 区如果没有足够的空间时会引发一次 young 区的 GC。从年轻代 (包括 Eden 和 Survivor 区域) 回收内存被称为 Minor GC。
注意
年轻代 gc 使用 “停止 - 复制” 算法,停止指的是,发生 GC 的时候会暂停除了 GC 线程以外的所有线程的运行。所以年轻代频繁 gc 会极大影响系统吞吐量
Survivor
在经历一次 eden 的 MinorGC 之后,Eden 中的存活对象就会被移动到第一块 survivor0,此时 Eden 被清空;Eden 区和 s0 满了之后,就再触发下一次 Minor GC,Eden 和 S0 中的存活对象会被复制送入 survivor1;此时 S0 和 Eden 被清空,然后下一轮 S0 与 S1 交换角色(两个存活区采用轮回机制,总有一个是空的)。如果 Survivor 的空间不足或者超过年轻代生存年龄(可以设置)的对象还能在新生代中存活,会通过分配担保机制将其送入老年代。Survivor 的存在意义,就是减少被送到老年代的对象,进而减少 Full GC 的发生。
老年代 (old 区)
对象在年轻代存活超过一定年龄(可以设置)没有被回收掉,就会被复制到老年代。老年代的空间比年轻代大,发生的 GC 次数也比年轻代少。但是 gc 时间大约是年轻代的 10 倍。
年轻代空间太小会导致对象直接进入 old 区 ,old 区满了就会触发 full gc。但是空间如果过大会引起回收耗时过长,导致应用阻塞。空间过小会产生 old 区小碎片,放不下大对象,引起频繁 full gc。从老年代 GC 称为 Major GC。
大对象会直接进入老年代(避免频繁复制)
年轻代对象年龄达到存活年龄阈值也会进入老年代
survivor 区太小,只能进入老年代
注意
老年代使用 “标记 - 整理” 算法,即将存活的对象向一边移动,以此来保证回收后,内存依然是连续的,不会出现内存碎片。每次年轻代的 Eden 发生 Minor GC 时,虚拟机都会检查每次晋级老年代的大小是否大于老年代的剩余大小,如果大于则会触发 FULL GC
FullGC
执行 Minor GC(年轻代 GC) 的时候,JVM 会检查老年代中最大连续可用空间是否大于了当前新生代所有对象的总大小,如果大于,则直接执行 Minor GC(年轻代 GC),如果小于,JVM 会检查是否开启了空间分配担保机制,如果没有开启则直接改为执行 Full GC。如果开启担保机制,则 JVM 会检查老年代中最大连续可用空间是否大于历次晋升到老年代中的平均大小,如果小于则执行改为执行 Full GC,如果大于则会执行 Minor GC(年轻代 GC),如果 Minor GC(年轻代 GC) 执行失败则会执行 Full GC。频繁的 fullgc 会严重阻塞应用。
内存溢出类型
在年轻代 gc 后还存活的对象会被复制到老年代中。当老年代空间不足时,JVM 会对老年代和年轻代进行完全的垃圾回收(full GC)。如果 fullGC 后还是无法存放从 Survivor 复制过来的对象,就会出现 OOM(Out of Memory)
内存溢出也区分为好几种类型,常见的有下面几种
java.lang.OutOfMemoryError: Java heap space
原因:java 堆内存不够或者程序中有死循环;
解决:扩大堆内存空间
java.lang.OutOfMemoryError: GC overhead limit exceeded
原因:内存不足,GC 为了释放很小空间而占用大量时间时抛出异常
解决:
1、查看系统是否有使用大内存的代码或死循环;
2、通过添加 JVM 配置,来限制使用内存:
java.lang.OutOfMemoryError: PermGen space
原因:持久代内存不够
解决:调整 JVM 的配置:
< jvm-arg>-XX:MaxPermSize=128m< /jvm-arg>
< jvm-arg>-XXermSize=128m< /jvm-arg>
java.lang.OutOfMemoryError: Direct buffer memory
原因:栈溢出,方法调用层次过多或者线程栈太小。
解决:优化程序设计,减少方法调用层次;调整-Xss 参数增加线程栈大小。
调整-XX:MaxDirectMemorySize= 参数
< jvm-arg>-XX:MaxDirectMemorySize=128m< /jvm-arg>