JVM结构
- 类加载子系统: 类加载子系统加载类后,将类信息放到方法区,除了类信息外还有运行时常量池信息
- java堆: 堆在启动时建立,存放所有java实例,堆空间所有线程共享
- 直接内存: NIO会使用直接内存,读写频繁的场合会考虑使用直接内存
- 垃圾回收系统: 垃圾回收系统会对方法区,java堆和直接内存进行回收
- java栈: 每个线程都会有一个java栈,启动线程就创建栈,栈保存局部变量,方法参数
- 本地方法栈: 本地方法栈用于本地方法调用
- PC寄存器: 每个线程创建一个PC寄存器
新生代: eden区 S0区(from区) S1区(to区)
对象先分配到eden区,在一次新生代后,如果对象还存活则进入S0或者S1区,每经过一次新生代回收,年龄就会加1,当年龄到一定程度后被认为是老年对象,进入老年代
SimpleHeap s1=new SimpleHeap(1);
SimpleHeap s2=new SimpleHeap(2);
- -Xss 指定线程最大栈空间
- 局部变量表存在栈中,如果局部变量过多,每一次调用函数会占用更多的栈空间,最终导致嵌套可调用次数减少
- jdk1.7前参数-XX:MaxPermSize 设置永久区的大小,jdk1.7之后使用-XX:MaxMetaspaceSize 设置元数据区的大小
常用JVM参数
-XX:+PringGC
只要遇到GC就会打印日志,打印详细信息:-XX:PringGCDetails
-XX:+PrintGCTimeStamps
输出GC发生时间-XX:+PrintPrintGCApplicationConcurrentTime
打印应用程序执行时间-XX:+PrintGCApplicationStoppedTime
打印应用程序由于GC产生的停顿时间-XX:+PrintReferenceGC
跟踪软引用,弱引用,虚引用和FinaFinallize队列-Xloggc:log/gc.log
打印日志到文件
堆参数设置
- 一般设置初始堆
-Xms
和最大堆-Xmx
设置相等,有利于减少垃圾回收次数 -Xmn
设置新生代的大小,一般设置为整个堆空间的1/3或1/4-XX:SurvivorRatio
设置新生代中Eden空间和from/to空间比例关系 eden/from=eden/to- -XX:SurvivorRatio设置后不生效:
原来,在HotSpot VM里,并行系的收集器(UseParallelGC / UseParallelOldGC)默认开启-XX:+UseAdaptiveSizePolicy, 这个配置会在每次Minor GC之后对From和To区进行自适应分配大小,而SurvivorRatio使用默认值8,设置成任何非8的数值都会无效。所以,我这个参数里面的-XX:+UseAdaptiveSizePolicy其实是画蛇添足了
垃圾回收算法
引用计数法, 标记压缩法, 标记清除法, 复制算法, 分代分区算法
- 新生代: 复制算法
- 老年代: 标记压缩算法,标记清除算法
- 软引用: GC未必会回收弱引用对象,当内存资源紧张的时候会回收
- 弱引用: GC每次发现都会回收
- 虚引用: 如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收
垃圾回收器
- 串行收集器
- 新生代串行收集器
- 复制算法
- 单线程, 独占式, 进行回收的时候所有线程要停止工作 +XX:+UseSerialGC
- 老年代串行收集器:
- 标记压缩算法
- 较大应用程序会停顿很长时间
- -XX:+UseSerialGC 新, 老年代都用串行收集器
- -XX:+UseParNewGC 新生代用并行回收器, 老年代用串行
- -XX:+UseParallelGC 新生代用ParaParallelGC, 老年代用串行
- 新生代串行收集器
- 并行收集器
-
新生代ParNew回收器
- 复制算法
- 简单地用多线程代替单线程, 程序会停顿
- -XX:+UseParNewGC 新生代用ParNew,老年代用串行
- -XX:+UseConcMarkSweepGC 新生代用ParNew, 老年代用CMS
- -XX:+ParallelGCThreads 指定回收线程数,一般和cpu数量相当
-
新生代ParallelGC回收器
- 复制算法
- 重要参数:
- -XX:MaxGCPauseMillis: 最大垃圾收集停顿时间,如果设置得太小,会导致jvm新建一个较小的堆,加多垃圾回收频率,所以不是越小越好
- -XX:GCTimeRatio: 默认值是19,意思是不超所1%的时间用于垃圾回收
- -XX:+UseAdaptiveSizeProxy: 打开自适应GC策略,手工调整比较困难的时候,只要设置最大堆, 目标吞吐量, 停顿时间, 让虚拟机自己完成调优
-
老年代ParallelOldGC回收器
- 标记压缩算法
- -XX:+UseParUseParallelGC 新生代用ParallelGC回收器,老年代用ParallelOldGC回收器
-
- CMS收集器
- 主要关注系统停顿时间
- 使用标记清除算法,多线程垃圾回收器,非独占式
- 初始标记(独占), 并发标记, 预清理, 重新标记(独占), 并发清除, 并发重置
- 启用CMS垃圾回收器 -XX:+UseConcMarkSweepGC
- -XX:CMSSInitiatingOccupancyFraction 指定回收阈值,默认是68,当老年代空间使用率达到68会执行一次回收,如果内存增长快,在CMS过程中已经出现了内存不足情况,这个时候CMS会失败,虚拟机自动启动老年代的串行收集器,让程序停顿,直到垃圾回收完成
- 当执行标记清除算法后,会存在不完整的内存碎片,需要用
-XX:+UseCMSCompactAtFullCollection
设置当进行多少次CMS回收后,进行一次内存压缩
- G1收集器
- 新生代GC, 并发标记周期(初始标记, 根区域扫描, 并发标记, 重新标记, 独占清理, 并发清理阶段), 混合回收(), 需要则进行FullGC
- G1会优先回收垃圾比例较高的区域
- -XX:+UseG1GC 打开G1收集器开关
- -XX:MaxGCPauseMillis 指定目标最大停顿时间
- -XX:ParallelGCThreads 设置并行回收时,GC工作线程数量
- 大对象当Eden空间不够时,会直接进入老年代,但是体积不是太大的对象有可能优先在TLAB中分配
- 不推荐使用Finalize()原因
性能监控工具
- 系统性能监控:top, vmstat 监控内存和cpu, iostat 监控IO
- jvm性能监控工具
jstat -gc 20212
查看各个空间的情况
jstat -gccause 20212
查看最近GC的原因
jinfo -flag MaxTenuringThreshold 20212
查看某个参数的设置值,还可以动态开关参数jinfo -flag +PrintGCDetails 20212**
jmap -histo 20212 > D:aaa.txt
获取对象统计信息
jmap -dump:format=b,file=D:aa.hprof 20212
生成堆快照,然后用jdk自带工具jvisualvm打开hprof文件可以看到哪个对象很大,帮助定位问题
jmap -finalizerinfo 20212
查看对象有没有堆积在finalizer队列中
jstack -l 16016 > D:d.txt
查看死锁原因
分配的堆空间太小
深入理解jvm和jvm基本调优参数 https://blog.csdn.net/zhangcongyi420/article/details/89060802