方法区,堆是所有线程共有。
保存class文件加载后的类信息,常量池数据等
1.8后叫metaspace
会OOM,如动态加载类文件时: java.lang.OutOfMemoryError: PermGen space
最大的内存区域,所有线程共享,保存对象和数组。
所有对象都存在堆中吗?
永久代并不属于堆内存中的一部分,jdk1.8之后永久代。
会OOM: java.lang.OutOfMemoryError: Java heap space
各个线程私有
保存栈帧
栈帧:每个方法被执行的时候创建,用于存储局部变量表(包括参数)、操作栈、方法出口等信息。
会栈溢出:java.lang.StackOverflowError
会OOM: JVM实现支持动态扩展时会,HotSpot不支持,不会OOM
保存native方法栈帧
会栈溢出
会OOM
各个线程私有
记录正在执行的JVM字节码指令位置
native方法执行时为空
不会OOM
标记-清理:标记出垃圾对象,清除垃圾对象
并发收集和清理,停顿较低,碎片多。
jdk1.9默认的回收器
控制回收时间:控制回收垃圾的时间,选择回收成本最低的Regions作为回收目标,达到实时收集的目的
空间整理:空间碎片较少,有效的使用了连续空间,不会导致连续空间不足提前造成GC的触发
内存拆分:把内存拆分成多等份(Region),逻辑上存在新生代和老年代的概念,无严格区分
实时数据占用超过一半的堆空间
对象分配或者晋升的速度变化大
希望消除长时间的GC停顿(超过0.5-1秒)
使用范围不同
CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用
G1收集器收集范围是老年代和新生代。不需要结合其他收集器使用
STW的时间
CMS收集器以最小的停顿时间为目标的收集器。
G1收集器可预测垃圾回收的停顿时间(建立可预测的停顿时间模型)
垃圾碎片
CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片。
G1收集器使用的是“标记-整理”算法,进行了空间整合,降低了内存空间碎片。
JVM内存调优主要目标是减少GC频率和耗时。GC包括以下几种
Minor GC:又叫young gc, 年轻代垃圾回收,主要采用复制清理算法。G1 GC也有youngGC
Full GC:又叫Major GC, old GC
主要关注GC次数,GC耗时,线程数曲线,内存晋升分配,内存各区域折线
jmap命令
jmap -heap pid //堆及新生代内存占用
jmap -histo pid | jmap -histo:live pid //查看对象个数及大小
jmap -dump:format=b,file=heap.hprof pid //导出内存文件
jmap -dump:live,format=b,file=heapLive.hprof pid//只导出存活的对象
内存dump:Java 线程&内存在线分析 说明文档
内存分析:VisualVM 或者 JProfiler
jtack命令
参考jstack — 查看堆栈信息
jstack -l pid//查看线程状态,打印锁相关日志。 有死锁会打印:Found one Java-level:deadlock
top -Hp pid //查看某个进程内各个线程的CPU占用。 jstack pid>thread.txt //dump线程信息到文本文件中。
NEW :线程创建未启动,不会出现在Dump中。
RUNNABLE:运行状态。
BLOCKED:受阻塞状态并等待监视器锁。
WAITING:无限期等待另一个线程执行特定操作。
TIMED_WAITING:有时限的等待另一个线程的特定操作。
TERMINATED:已退出的状态。
runnable:状态一般为RUNNABLE。
in Object.wait():等待区等待,状态为WAITING或TIMED_WAITING。
waiting for monitor entry:进入区等待,状态为BLOCKED。
waiting on condition:等待区等待、被park。
sleeping:休眠的线程,调用了Thread.sleep()。
locked :使用synchronized申请对象加锁成功,成为监视器的拥有者。
waiting to lock :使用synchronized申请对象锁未成功,在进入区等待。
waiting on :使用synchronized申请对象锁成功后,释放锁幵在等待区等待。
parking to wait for 基本的线程阻塞原语,不通过监视器在对象上阻塞。和Concurrent包一起出现,如ReentrantLock
死锁分析
CPU占用分析
top命令查到的线程号是10进制,jstack中打印的线程号是16进制,要把10进制转为16进制去查看
GC日志开关
-XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+PrintGCDetails
PrintGC必须开启,只开启PrintGCDetails、PrintGCTimeStamps不会输出GC
查看是否开启GC日志打印
admin@M-C02FXLJ1MD6M:~$ jinfo -flag PrintGC 11871 -XX:-PrintGC// 减号说明没有打开日志
动态设置GC开关: jinfo
-flag pid:打印指定JVM的参数值
-flag [+|-] pid:设置指定JVM参数的布尔值
-flag = pid:设置指定JVM参数的值
//打开GC开关 jinfo -flag +PrintGC 2345
Minor GC执行耗时小于50ms;
Minor GC执行频率较低,小于10秒一次;
Full GC执行耗时小于1s;
Full GC执行频率较低,小于10分钟1次;
标准类型: -version -help。 各个JVM都会支持,一般不会变动 X参数:非标准参数(变动比较小),并且默认jvm实现这些参数的功能。如-Xcomp、-Xmixed。 XX参数:不稳定参数,各个JVM实现可能不同。 如-XX:+UseConcMarkSweepGC、-XX:+UseG1GC,-XX:MaxGCPauseMillis=500
-Xms(memory start):初始堆大小,一般初始值可以和最大值设一样,避免GC后内存重新分配。
-Xmx(memory max):最大堆大小。
-Xmn(memory new):新生代大小。
-XX:NewRatio:新生代(Eden+2 survivor space)与老年代(除去持久代)的比值
-Xss(stack size):每个线程的堆栈大小。
-XX:MaxTenuringThreshold:年轻代最大年龄。
-XX:PretenureSizeThreshold:对象超过多大时直接在老年代分配,默认值0,单位字节。
-XX:ParallelGCThreads:并行收集器的线程数。
-XX:+DisableExplicitGC:禁止System.gc(),免得程序员误调用gc方法影响性能。
-XX:CMSFullGCsBeforeCompaction:CMS不对内存空间进行压缩、整理,这里配置多少次FullGC后进行内存压缩
-XX:+PrintGC
-XX:+PrintGCDetails
XX:+PrintGCApplicationStoppedTime:打印GC期间程序暂停时间
-XX:PrintHeapAtGC:打印GC前后的详细堆栈信息
-Xloggc:filename:设置GC日志位置
-XX:MaxGCPauseMillis:最大停顿时间。
不要设置-Xmn, -XX:NewRatio. G1会动态调整年轻代大小,以满足最大停顿时间。
-XX:G1HeapRegionSize = n 设置region大小
-XX:InitiatingHeapOccupancyPercent = 45 设置触发GC的堆占用百分比
-XX:G1NewSizePercent = 5 设置要用作年轻代大小的最小值的堆百分比。默认值为Java堆的5%
-XX:G1MaxNewSizePercent = 60 设置堆大小的百分比,以用作年轻代大小的最大值。默认值为Java堆的60%