吞吐量:CPU运行代码的时间和CPU 总共消耗时间的比值。
在Java中,我们知道,内存的分布主要式堆和栈,栈会随着线程的结束而销毁,因此我们不需要考虑栈内存的回收,我们只需要考虑堆的垃圾回收,忽略其他内存的回收。
在JVM 运行的不同时期,使用不同的垃圾回收算法。
在Java 中,并没有明确的说明JVM使用哪种垃圾回收算法,但是任何一种垃圾回收算法都必须做两种事:
① 发现无用的信息对象 ②回收无用的垃圾对象占用的内存
在这之前,我们首先要了解垃圾收集器和垃圾回收器算法,在虚拟机中,我们可以选择一种垃圾回收器,每种垃圾回收器使用不同的算法进行回收。
jdk1.7 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)jdk1.9 默认垃圾收集器G1-XX:+PrintCommandLineFlagsjvm参数可查看默认设置收集器类型-XX:+PrintGCDetails亦可通过打印的GC日志的新生代、老年代名称判断
垃圾回收器的算法:
引用计数算法
给对象中添加一个引用计数器,每当一个地方引用他的时候,计数器就加一,当引用失效的时候,计数器就减一(这个算法实现简单/效率高,但是有个缺陷很难解决相互引用的问题)
可达性分析算法
通过起始节点GC roots ,从这些节点往下搜索,搜索所走过的路径引用连接,当一个对象中没有任何引用链相连接,则证明对象不可用
在Java语言中,可作为roots 的有:①虚拟机栈中的引用对象 ② 方法区中静态属性的引用对象 ③ 方法区中常量引用对象 ④本地方法栈中引用的对象
在这过程中,当内存空间足够的话,我们希望能够保留在内存中,所以java就对引用进行了扩充,就是强引用/软引用/弱引用/虚引用
当对象不可达时,他们并非时非死不可,要宣告死亡,最少要经历2次标记的过程, 第一次标记并筛选条件是,是否有必要执行finalize(),当对象没有覆盖这个方法,或者这个方法已经被虚拟机调用过了,则判断没有必要执行,
当有必要执行执行,放入队列等待清除,在这过程中,对象可能会逃脱出来。
标记-清除算法
算法分为标记和清除两部分,首先标记出所有需要清除的对象,在标记完成之后, 同意回收所有被标记的对象。(标记和清除效率并不高)
复制算法
为了解决效率的问题,这种算法出现了,他将可用内存按照大小分为两部分,每次只使用其中的一块,当这块的内存使用完之后,就将还存活的对象复制到另外一块上面,然后把已经使用过的内存空间一次性清理掉,(简单高效,但是内存缩小为原先一半)
这样是对整个半内存进行回收,也不用考虑碎片的问题。
研究表明,新生代中的对象98% 是朝生夕死,所有没有必要按照1:1 进行分配,而是将内存分配为一个较大的Eden 和两块较小的Survivor ,当进行回收的时候,将Eden 和其中一块Survivor 还存活的对象一次性复制到另外一块Survivor 上面,然后清理掉
刚才那两块内存,这样就相当于只有10% 的内存会被浪费,如果另外一块内存没有足够的空间保存存活的对象,会将这些对象通过分配机制进入老年代,
标记整理算法
复制算法是在对象存活相对较高的情况下,复制效率会变低,更关键的是如果不想浪费内存,就需要额外的内存担保,所以老年代中一般不会选用这样算法
标记过程仍然和标记-清除相同,但是后续不同,就是让所有存活的对象都向一端进行移动,然后直接清理掉界限以外的数据。
分代收集算法
根据对象的存活周期,将内存分为几块,然后分别使用不同的算法
GC 日志
每一个收集器日志的格式都不相同,但为了方便,各个之间也有共性 -XX:+PrintGCDetails 可以进行查看
[GC (Metadata GC Threshold) [PSYoungGen: 26326K->4600K(61952K)] 30735K->11354K(138752K), 0.0121680 secs] [Times: user=0.01 sys=0.01, real=0.01 secs] [Full GC (Metadata GC Threshold) [PSYoungGen: 4600K->0K(61952K)] [ParOldGen: 6754K->7125K(48128K)] 11354K->7125K(110080K), [Metaspace: 20582K->20580K(1067008K)], 0.0652552 secs] [Times: user=0.09 sys=0.00, real=0.07 secs]
GC和Full GC 是区分垃圾收集的停顿类型
PSYoungGen 发生的区域
26326K->4600K(61952K) GC前该内存区域已经使用容量-> GC后该区域使用区域容量(该内存区域的总容量) 方括号外面 30735K->11354K(138752K) GC 前堆已经使用容量->GC后堆使用容量(堆总容量)
0.0121680 secs 在该内存区域垃圾回收占用的时间,单位是秒
参数 | 描述 |
---|---|
UseSerialGC | 虚拟机运行在Client模式下的默认值,打开此开关后,使用Serial + Serial Old的收集器组合进行内存回收 |
UseParNewGC | 打开此开关后,使用ParNew + Serial Old的收集器组合进行内存回收 |
UseConcMarkSweepGC | 打开此开关后,使用ParNew + CMS + Serial Old的收集器组合进行内存回收。Serial Old收集器将作为CMS收集器出现Concurrent Mode Failure失败后的后备收集器使用 |
UseParallelGC | 虚拟机运行在Server模式下的默认值,打开此开关后,使用Parallel Scavenge + Serial Old(PS MarkSweep)的收集器组合进行内存回收 |
UseParallelOldGC | 打开此开关后,使用Parallel Scavenge + Parallel Old 的收集器组合进行内存回收 |
SurvivorRatio | 新生代中Eden区域与Survivor区域的容量比值,默认为8,代表Eden : Survivor=8:1 |
PretenureSizeThreshold | 直接晋升到老年代的对象大小,设置这个参数后,大于这个参数的对象将直接在老年代分配 |
MaxTenuringThreshold | 晋升到老年代的对象年龄。每个对象在坚持过一次Minor GC之后,年龄就增加1,当超过这个参数值时就进入老年代 |
UseAdaptiveSizePolicy | 动态调整Java堆中各个区域的大小以及进入老年代的年龄 |
HandlePromotionFailure | 是否允许分配担保失败,即老年代的剩余空间不足以应付新生代的整个Eden和Survivor区的所有对象都存活的极端情况 |
ParallelGCThreads | 设置并行GC时进行内存回收的线程数 |
GCTimeRatio | GC时间占总时间的比率,默认值为99,即允许1%的GC时间。仅使用Parallel Scavenge收集器时生效 |
MaxGCPauseMillis | 设置GC的最大停顿时间。仅在使用Parallel Scavenge收集器生效 |
CMSInitiatingOccupancyFraction | 设置CMS收集器在老年代空间被使用多少后触发垃圾收集,默认值为68%,仅使用CMS收集器时生效 |
UseCMSCompactAtFullCollection | 设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理。仅在使用CMS收集器时生效 |
CMSFullGCsBeforeCompaction | 设置CMS收集器在进行若干次垃圾收集后再启动一次内存碎片整理。仅在使用CMS收集器时生效 |