对象通常在堆上分配,但JVM支持一种在栈上分配内存的机制。
经过-XX:+DoEscapeAnalysis
开启逃逸分析
(默认开启),JVM会针对不会逃逸的对象分配在栈上。好处是,栈能够自动弹出,不须要垃圾回收参与处理这些对象。html
此外TLAB(Thread Local Allocation Buffer)是一个线程独占的堆空间。通常的堆空间是共享的,在内存分配时,多个线程须要同步,但TLAB区域因为线程独占,因此没必要在分配内存时进行同步。TLAB自己占用eden区域。java
关于逃逸分析
和TLAB
参见jvm 优化篇-(4)-栈上分配与逃逸分析 -XX:+DoEscapeAnalysis -XX:+UseTLAB -XX:TLABRefillWasteFraction算法
现代垃圾回收的基本算法是标记清除(Mark-Sweep),但依然要面临内存碎片的问题。JVM采用分代机制解决内存碎片问题。多线程
新生代采用复制算法。新生代的特色是,大部分对象是能够回收的。新生代区进一步分为eden区、from区、to区。from区和to区是两块大小相同内存区域,有时也叫S0/S1,做用是交换存活对象。新生代内存分配发生在eden区。当新生代须要垃圾回收时,假设此时S0中是上一次GC留下来的存活对象,那么eden中的存活对象和S0中的对象都将复制到S1(并对齐),而后eden和S0能够直接清空;下一次垃圾回收时,eden和S1的存活对象复制到S0(并对齐)。因此说S0和S1相互交换存活对象。若是S0和S1没法容纳对象,那么部分对象将进入老年代区。因为新生代中大部分对象是能够回收的,因此采用这种复制算法压缩内存最为高效。并发
老年代采用标记压缩算法。由于老年代活动对象多,垃圾对象少。jvm
G1采用分区算法。分区的思想是将推内存划分为多个区,若是每次只收集若干区域,而不是整个堆,能够有效的控制停顿时间。函数
垃圾回收器经历了串行、并行(多线程)、并发(不阻塞应用)的发展。参考[深刻JVM读书笔记(四)——Java的垃圾收集器]性能
早期的垃圾收集器能够组合使用,以下图优化
G1收集器的整体效果是好于CMS的,有更好的自我调节能力而G1从JDK9开始才是默认垃圾回收器。因此JDK8的状况下,最好主动设置G1垃圾回收器:spa
-XX:+UseG1GC
G1收集器用Region来划份内存,虽然逻辑上依然保留新生代和老年代,可是新生代和老年代是由若干Region组成的,而且并不必定要求连续。每一个分区Region也不会肯定地为某个代服务,能够按需在新生代和老年代之间切换。
18.657: [GC pause (G1 Evacuation Pause) (young) (initial-mark) 26M->24M(32M), 0.0025448 secs] 18.659: [GC concurrent-root-region-scan-start] 18.660: [GC concurrent-root-region-scan-end, 0.0008815 secs] 18.660: [GC concurrent-mark-start] 18.696: [GC concurrent-mark-end, 0.0357099 secs] 18.696: [GC remark, 0.0037490 secs] 18.703: [GC cleanup 24M->24M(32M), 0.0004163 secs] 18.892: [GC pause (G1 Evacuation Pause) (young) 26M->25M(32M), 0.0027587 secs] 19.014: [GC pause (G1 Evacuation Pause) (mixed) 26M->24M(32M), 0.0042025 secs]
上面是一段G1的gc日志
并发标记可能被young gc和full gc打断,例以下面的日志展现了被full gc中断的concurrent-mark
34.036: [GC concurrent-mark-start] 34.037: [Full GC (Allocation Failure) 31M->31M(32M), 0.0912206 secs] 34.128: [Full GC (Allocation Failure) 31M->31M(32M), 0.0905478 secs] 34.219: [GC concurrent-mark-abort] 34.219: [GC pause (G1 Evacuation Pause) (young) 31M->31M(32M), 0.0084531 secs] 34.228: [GC pause (G1 Evacuation Pause) (young) (initial-mark) 31M->31M(32M), 0.0067091 secs]
总结
选项 | 说明 |
---|---|
-XX:MaxGCPauseMillis | 设置最大GC停顿时间(GC pause time)指标(target). 这是一个软性指标(soft goal), JVM 会尽可能去达成这个目标. |
-XX:InitiatingHeapOccupancyPercent | 启动并发GC周期时的堆内存占用百分比. G1之类的垃圾收集器用它来触发并发GC周期,基于整个堆的使用率,而不仅是某一代内存的使用比. 值为 0 则表示"一直执行GC循环". 默认值为 45 |
-XX:ParallelGCThreads | 设置垃圾收集器在并行阶段使用的线程数,默认值随JVM运行的平台不一样而不一样 |
jstat -gc <pid>
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 1088.0 1088.0 0.0 117.2 8704.0 8641.6 21888.0 21888.0 24832.0 24320.1 2560.0 2340.1 26 0.134 13 0.810 0.944
年轻代垃圾回收次数
年轻代垃圾回收消耗时间
老年代垃圾回收次数
老年代垃圾回收消耗时间
查看进程的jvm flag
。例如,验证DoEscapeAnalysis
默认是开启的
$ jinfo -flag DoEscapeAnalysis 6953 -XX:+DoEscapeAnalysis
也能够动态修改部分参数
$ jinfo -flag +PrintGCDetails 6953