JVM系列学习(四):JVM的内存分析
文章目录
- JVM的内存结构(JDK1.8)
- 垃圾回收算法
- 垃圾收集器
- 串行收集器Serial:Serial,Serial Old
- 并行收集器Parallel:Parallel Scavenge,Parallel Old,吞吐量优先
- 并发收集器Concurrent:CMS,G1,停顿时间优先
- 并行 VS 并发
- 停顿时间VS吞吐量
- 垃圾收集器搭配
- [如何选择垃圾收集器](https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html)
- [GC调优指南](https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/toc.html)
JVM的内存结构(JDK1.8)
运行时数据区:官方文档
- 程序计数器PC Register:
- 虚拟机栈JVM Stacks:
- 堆Heap:
- 方法区Method Area:
- 常量池Run-Time Constant Pool:
- 本地方法栈:Native Method Stacks:
非堆区Metaspace
- Metaspace=Class,Package,Method,Field,字节码,常量池,符号引用等等
- CSS:32位指针的Class,压缩空间(64位指针变为32位指针)
- CodeCache:JIT编译后的本地代码,JNI使用的C代码
常用参数
- -Xms -Xmx
- -XX:NewSize -XX:MaxNewSize
- -XX:NewRatio -XX:SurvivorRatio
- -XX:MetaspaceSize -XX:MaxMetaspaceSize
- -XX:+UserCompressedClassPointers
- -XX:CompressedClassSpaceSize
- -XX:InitialCodeCacheSize
- -XX:ReservedCodeCacheSize
垃圾回收算法
工作原理
- 思想:枚举根节点,做可达性分析。这是Java虚拟机采用的判定对象是否存活的算法。通过一系列的称为“GC Roots"的对象作为起始点,从这些结点开始向下搜索,搜索所走过的路径称为饮用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。可作为GC Roots的对象包括:虚拟机栈中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象。本地方法栈JNI引用的对象
- 根节点:类加载器,Thread,虚拟机栈的本地变量表,static成员,常量引用,本地方法栈的变量等等
标记清除
- 算法:算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收
- 缺点:效率不高。标记和清除两个过程的效率都不高。产生碎片。碎片太多会导致提前GC
复制
-
算法
它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
-
优缺点
实现简单,运行高效,但是空间利用率低,只有50%空间。
标记整理
-
算法
标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
-
优缺点
没有了内存碎片,但是整理内存比较耗时
分带垃圾回收:JVM采用的方法
- Young区用复制算法
- Old区标记清除或者标记整理算法
对象分配
- 对象优先再Eden区分配
- 大对象直接进入老年代:-XX:PretenureSizeThreshold参数来决定
- 长期存活对象进入老年代
- -XX:MaxTenuringThreshold参数来决定存活几次
- -XX:+PrintTenuringDistribution
- -XX:TargetSurvivorRatio
垃圾收集器
串行收集器Serial:Serial,Serial Old
- 主要应用于嵌入式设备,WEB场景不可能使用
- 开启串行收集器:-XX:+UseSerialGC -XX:+UseSerialOldGC
并行收集器Parallel:Parallel Scavenge,Parallel Old,吞吐量优先
- 吞吐量优先
- -XX:+UseParallelGC,-XX:+UseParallelOldGC
- Server模式下的默认收集器,会根据服务器的配置来启动Client或者Server模式
Parallel Collector:暂停应用程序,启动多个回收器来回收
- -XX:+UseParallelGC手动开启,Server默认开启
- -XX:ParallelGCThreads=多少个GC线程
-
- CPU>8 N=5/8
- CPU<8 N=CPU
Parallel Collector Ergonomics 自适应
- -XX:MaxGCPauseMillis= 优先满足停顿时间的情况下满足吞吐量
- -XX:GCTimeRatio=
- -Xmx
动态内存调整参数
- -XX:YoungGenerationSizeIncrement=
- -XX:TenuredGenerationSizeIncrement=
- -XX:AdaptiveSizeDecrementScaleFactor=
并发收集器Concurrent:CMS,G1,停顿时间优先
- 响应时间优先
- CMS:-XX:+UseConcMarkSweepGC -XX:+UseParNewGC
- G1:-XX:+UseG1GC
CMS Collector
- 并发收集,低停顿,低延迟, 并且是一个老年代收集器
- CMS垃圾收集过程
-
- CMS initial mark:初始标记Root,STW
- CMS concurrent mark:并发标记
- CMS-concurrent-preclean:并发预清理
- CMS remark:重新标记,STW
- CMS concurrent sweep:并发清除
- CMS-concurrent-reset:并发重置
- CMS的缺点
-
- CPU敏感:一个CPU全部都是我的
- 浮动垃圾
- 空间碎片
- CMS的相关参数
- -XX:ConcGCThreads:并发的GC线程数
- -XX:+UseCMSCompactAtFullConnection:FullGC之后做压缩
- -XX:CMSFullGCBeforeCompaction:多少次FullGC之后做压缩一次
- -XX:CMSInitiatingOccupancyFraction:触发FullGC
- -XX:+UseCMSInitiatingOccupancyOnly:是否动态调整
- -XX:+CMSScavengeBeforeRemark:FullGC之前先做YGC
- -XX:+CMSClassUnloadingEnabled:启用回收Perm区
- iCMS
- 适用于单核或者双核
G1 Collector
- 新生代和老生代收集器
- Region
- SATB:Snapshot-At-The-Beginning,它是通过Root Tracing得到的,GC开始时候存活对象的快照
- RSet:记录了其他Region中的对象引用本Region中对象的关系,属于points-into结构(谁引用了我的对象)
- YoungGC
-
- 新对象进入Eden区
- 存活对象拷贝到Survivor区
- 存活时间达到年龄阈值时,对象晋升到Old区
- MixedGC
-
- 不是FullGC一样回收所有的Young和部分Old
- global concurrent marking全局并发标记
-
- Inital marking phase:标记GC Root,STW
- Root region scanning phase:标记存活Region
- Concurrent marking phase:标记存活的对象
- Remark phase:重新标记,STW
- Cleanup phase:部分STW
- MixedGC时机
-
- InitiatingHeapOccupancyPercent: 堆占有率达到这个数值则触发global concurrent marking,默认45%
- G1HeapWastePercent: 在global concurrent marking结束之后,可以知道区有多少空间要被回收,在每次YGC之后和再次发生Mixed GC之前,会检查垃圾占比是否达到此参数,只有达到了,下次才会发生Mixed GC。
- G1MixedGCLiveThresholdPercent: Old区的region被回收时候的存活对象对比
- G1MixedGCCountTarget: 一次global concurrent marking之后,最多执行Mixed GC的次数
- G1OldCSetRegionThresholdPercent: 一次Mixed GC中能被选入CSet的最多old区的region数量
- 常用参数
-
- -XX:+UseG1GC 开启G1
- -XX:G1HeapRegionSize=n,region的大小,1-32M,2048个
- -XX:MaxGCPauseMillis=200 最大停顿时间
- -XX:G1NewSizePercent,-XX:G1MaxNewSizePercent
- -XX:G1ReservePercent=10 保留防止to space溢出
- -XX:ParallelGCThreads=n SWT线程数
- -XX:ConcGCThreads=n 并发线程数=1/4*并行
- 最佳实践
-
- 年轻代大小:避免使用-Xmn,-XX:NewRatio等显式设置Young区大小,会覆盖暂停时间目标
- 暂停时间目标:暂停时间不要太严苛,其吞吐量目标是90%的应用程序时间和10%的垃圾回收时间,太严苛会直接影响到吞吐量
- MixedGC调优
- 是否需要切换到G1
-
- 50%以上的堆被存活对象占用
- 对象分配和晋升的速度变化非常大
- 垃圾回收时间特别长,超过了1秒
- G1 GC的一些关键技术
并行 VS 并发
- 并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。适合科学计算,后台处理等弱交互场景。
- 并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),垃圾收集线程在执行的时候不会停顿用户程序的运行。适合对响应时间有要求的场景,比如Web
停顿时间VS吞吐量
- 理想情况:吞吐量最大的时候停顿时间最小,现实情况两者是互斥的
- 停顿时间:垃圾收集器做垃圾回收中断应用执行的时间 -XX:MaxGCPauseMillis
- 吞吐量:花在垃圾收集的时间和花在应用时间的占比。 -XX:GCTimeRatio=,垃圾收集时间占:1/1+n
垃圾收集器搭配
如何选择垃圾收集器
- 优先调整堆的大小让服务器自己来选择
- 如果内存小于100M,使用串行收集器
- 如果是单核,并且没有停顿时间的要求,串行或者JVM自己选
- 如果允许停顿时间超过1秒,选择并行或者JVM自己选
- 如果响应时间最重要,并且不能超过1秒,使用并发收集器
GC调优指南
- JDK1.8下,优先查看官方文档来进行调优指南的学习