1. jvm 内存模型
堆,元空间,栈,本地方法栈,程序计数器
堆: 存放引用对象位置
元空间:存放类,方法,静态变量,常量
程序计数器:保存线程执行的上下文
栈: 方法执行需要使用的内存位置
本地方法栈: java native修饰的原生方法调用时使用的栈
2. 堆内存分代模型
新生代:老年代= 1:2
新生代包含 eden:s1:s2 = 8:1:1
新创建对象在eden,minior gc一次放在s1,下次gc 放在s2,如果在存放到s区放不对象时,直接丢到老年代
minior gc 检查对象的代数,超过一定值也会放到老年代中
老年代放满触发major gc
如果major gc内存仍然不够触发一次full gc,如果够新对象分配程序正常运行
频繁full gc是gc后内存刚好够分配,这种情况要排查内存设置过小,内存泄漏两种问题。 大概率是方法区内存不够,静态变量对象内存泄漏问题引起
full gc内存仍然不够oom 这种情况要排查内存设置过小,内存泄漏两种问题排查
3. gc回收器标识
垃圾回收器算法
标识 | 说明 | 备注 |
---|---|---|
-XX:+UseSerialGC | 新生代使用Serial,老年代使用Serial Old | 单线程的垃圾回收器。 回收器gc日志标识,新生代:Copy,老年代 MarkSweepCompact |
-XX:+UseParNewGC | 新生代使用ParNew,老年代使用Serial Old | 回收器gc日志标识,新生代:PS Scavenge,老年代:PS MarkSweep |
-XX:+UseParallelGC | 新生代使用ParallelScanvenge,老年代使用Serial Old | 回收器gc日志标识,新生代:PS Scavenge,老年代:PS MarkSweep |
-XX:+UseParallelOldGC | 新生代使用ParallelScanvenge,老年代使用Parallel Old | 回收器gc日志标识,新生代:PS Scavenge,老年代:PS MarkSweep |
-XX:+UseConcMarkSweepGC | 表示新生代使用ParNew,老年代的用CMS,cms在回收失败时会调用Serial Old再进行回收 | 使用cms gc器时在jdk 1.8.0_261版本会自动给进程添加-XX:+UseParNewGC垃圾回收器。新生代使用parNew垃圾回收器,老年代优先使用cms,在cms回收失败会降级调用serial old。 回收器gc日志标识,新生代:ParNew,老年代:ConcurrentMarkSweep |
-XX:+UseG1GC | g1,新生代,老年代并用的回收器 | 回收器gc日志标识,新生代:G1 Young Generation,老年代:G1 Old Generation |
ParallelScanvenge 动态调整新生代的内存,可以通过-XX:-UseAdaptiveSizePolicy关闭动态调整策略
Serial Old 会动态调整老年代提交内存策略,目的是为了降低major gc(老年代)的时间。 目前没有找到可以关闭的参数
4. 查看默认参数
4.1 默认垃圾回收器查看
java -XX:+PrintCommandLineFlags -version
#-XX:InitialHeapSize=2147483648 -XX:MaxHeapSize=32210157568 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
java -XX:+PrintFlagsFinal -version | grep MaxMetaspaceSize 默认元空间大小
4.2 查看进程垃圾回收器
jinfo -flags pid
#jinfo -flags 247902 看最后一个标识符
#Non-default VM flags: -XX:CICompilerCount=15 -XX:InitialHeapSize=2147483648 -XX:MaxHeapSize=9563013120 -XX:MaxNewSize=2878930944 -XX:MaxTenuringThreshold=6 -XX:MinHeapDeltaBytes=196608 -XX:NativeMemoryTracking=null -XX:NewSize=715784192 -XX:OldPLABSize=16 -XX:OldSize=1431699456 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseFastUnorderedTimeStamps -XX:+UseParNewGC
4.3 默认堆外内存为0
java -XX:+PrintFlagsFinal -version | grep MaxDirectMemorySize
# uintx MaxDirectMemorySize = 0 {product}
# 输出为0 则代表走默认
java version "1.8.0_261" 默认使用+UseParallelGC
参数
Serial Old
单线程回收老年代内存,采用标记整理算法,
优点
- 能够保证老年代的内存回收
- 不存在内存碎片
缺点
- 单线程回收,针对大内存时回收效率低。 为了降低回收时间,默认采用动态分配申请内存机制,在空闲
老年代对象出发gc 条件
-
老年代内存不足
-
新生代对象无法放在老年代
-
新生代s1 s2关闭自动适配策略
关闭-XX:-UseAdaptiveSizePolicy
开启-XX:+UseAdaptiveSizePolicy
1. 内存参数设置
-Xmx10g 最大内存
-Xms10g 最小内存
-Xmn100m 新生代内存 一般不设置,默认设置内存的1/3
-XX:MaxMetaspaceSize=100m 最大元空间大小,一般不设置,默认无限大
-Xss2m 线程栈内存大小默认是2m,一般够用的。如果存在线程中大量的基本类型数据,需要设置调整这个大小
新生代,老年代的比例、大小一般不做调整。
新生代:老年代= 1:2
新生代包含 eden:s1:s2 = 8:1:1
2. gc器设置
cms gc参数
-XX:+UseConcMarkSweepGC 即CMS收集,设置年老代为并发收集。
-XX:+UseParNewGC 设置年轻代为并发收集。261版本会自行设置,无需再设。
-XX:+CMSParallelRemarkEnabled 默认开启,关闭则变成单线程标记,会增加gc时间
-XX:+UseFastAccessorMethods 默认关闭,开启jvm通过快速访问器方法来读取和写入对象字段
-XX:ParallelCMSThreads=xxx cms垃圾回收器在标记阶段,清理阶段的线程数,默认 小于8核,跟cpu核心数相同。 大于8核 5/8 * cpu核数 + 3; 过多设置会导致增大上下文切换和线程间通信开销,从而增大gc时间。建议使用默认参数
-XX:+UseCMSCompactAtFullCollection 打开开内存空间的压缩和整理,在Full GC后执行。 默认开启
-XX:CMSFullGCsBeforeCompaction=0 每次老年带GC后立刻开始压缩和整理内存。默认是0每次gc后都整理空间,设置次数,是在num次gc后整理一次空间。如果内存很大可以设置较大值,如果内存少,要设置较小值,具体的可以根据环境调整
-XX:+UseCMSInitiatingOccupancyOnly 启用设置阈值,默认开启
-XX:CMSInitiatingOccupancyFraction=70 表示年老代内存空间使用到70%时就开始执行CMS收集。 默认90%
-XX:MaxTenuringThreshold 进入老年代的代数,默认15
3. oom自动dump文件
-XX:+HeapDumpOnOutOfMemoryError 开启堆内存dump文件
-XX:HeapDumpPath=/app/logs/${app_name}/heapdump.hprof" 指定dump文件位置
4. 堆外内存设置
-XX:MaxDirectMemorySize=xxxm 堆外内存不设置默认跟堆内存大小一致。 内存会自动回收,垃圾回收器无法回收堆外内存的,堆外内存的垃圾回收原理是通过在分配空间时在堆内存创将两个对象 1. DirectByteBuffer,2. 以DirectByteBuffer实例创建的虚引用的cleaner对象,主要是在DirectByteBuffer对象被垃圾器回收后,cleaner对象会收到通知再讲堆外的内存进行回收掉
5. 文件编码设置
-Dfile.encoding=UTF-8
完整的的命令demo
java -Xmx10G -Xms10G -XX:+UseConcMarkSweepGC -Dfile.encoding=utf-8 -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:MaxTenuringThreshold=15 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs/hiveTest/heapdump.hprof -cp /tmp/hiveTest/hiveTest.jar:/tmp/hiveTest/conf:/tmp/hiveTest/lib/* org.tianzehao.App
为什么要选用cms
- 默认的gc器是-XX:+UseParallelGC 新生代使用ParallelScanvenge, 老年代使用Serial Old,新生代内存会根据使用情况动态调整以达到更小的回收时间,带来一个问题是老年代内存增长快。
老年代内存gc同样也会动态调整,以追求更快的回收时间,但是因为是单线程的,gc时间是减小工作量代价换来的,gc总的时间还是cms gc的时间长。
这个是2g 内存,如果内存更大,这个差距将会更明显
日常排查内存是否有泄漏
jmap -dump:live
jmap -histo:live 触发一次full gc; 如果监控中内存使用能够回落则正常,如果无法回落可能存在异常
jmap -histo pid |head -n 100 查看前100项最大内存
网友评论