java基础知识,垃圾回收机制
对象优先分配到Eden区
/**
* -XX:+PrintGCDetails 打印GC详情信息
* -XX:+PrintGC 打印GC信息
*/
public class TestPolicy1 {
private static final int _1MB = 1024 * 1024;
public static void testAllocation() {
byte[] allocation1, allocation2, allocation3, allocation4;
allocation1 = new byte[2 * _1MB];
allocation2 = new byte[2 * _1MB];
allocation3 = new byte[2 * _1MB];
allocation4 = new byte[4 * _1MB];
}
public static void main(String[] args) {
testAllocation();
}
}
大对象直接进入老年代
/**
* -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
* -XX:PretenureSizeThreshold=3145728 // 设置对象直接进入老年代的阈值。对SerialGC和ParNew起作用
*/
public class TestPolicy2 {
private static final int _1MB = 1024 * 1024;
/**
* VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
* -XX:PretenureSizeThreshold=3145728。默认值是0
*/
public static void testPretenureSizeThreshold() {
byte[] allocation;
// 直接分配在老年代中
allocation = new byte[4 * _1MB];
}
public static void main(String[] args) {
testPretenureSizeThreshold();
}
}
长期存活的对象会进入老年代
public class TestPolicy3 {
private static final int _1MB = 1024 * 1024;
/**
* VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90
* -XX:+PrintGCDetails
* -XX:MaxTenuringThreshold=1
* -XX:+PrintTenuringDistribution
* Jdk 1.7.0_46
*/
public static void testTenuringThreshold() throws InterruptedException {
byte[] allocation1, allocation2, allocation3;
allocation1 = new byte[_1MB / 4];
//什么时候进入老年代取决于XX:MaxTenuringThreshold设置
allocation2 = new byte[4 * _1MB];
allocation3 = new byte[4 * _1MB];
System.out.println("=============");
allocation3 = null;
allocation3 = new byte[4 * _1MB];
System.out.println("=============");
}
public static void main(String[] args) throws InterruptedException {
testTenuringThreshold();
}
}
动态年龄判断
如果在Survivor空间中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或者等于平均年龄的对象直接进入老年代。
空间担保
在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么Minor GC可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。
如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,或者HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC。
关于GC清理
MinorGC用于清理新生代,MajorGC清理老年代。FullGC清理新生代+老年代(方法区)
MinorGC触发条件:当新生代无法给新对象分配空间时。如:Eden区满了。
MajorGC触发条件:老年代没有空间。经历一次MinorGC
FullGC触发条件:
- System.gc
- 老年代空间不足
- 方法区空间不足
- 经过MinorGC后,进行的对象大小大于老年代的可用空间。Eden+From到To复制的时候,对象的大小大于To区域大小,当把对象转到老年,这个时候老年代的空间小于对象大小。
GC信息解读
[GC (Allocation Failure) [DefNew: 6518K->898K(9216K), 0.0038707 secs] 6518K->4994K(19456K), 0.0042538 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
GC (Allocation Failure) GC的类型,括号里面是GC产生的原因。
DefNew 垃圾回收期的名称
6518K->898K(9216K) 6518K代表GC之前大小,898K代表GC之后的大小。9216K总的大小。
0.0038707 secs GC暂停的时间。
6518K->4994K(19456K) 整个区域的情况。
[Times: user=0.00 sys=0.00, real=0.00 secs]
user 执行GC期间线程消耗的总CPU时间
sys 操作系统调用或者等待系统事件等待的时间
real 应用程序停止的时间。
FullGC(xxxxxxx)
- FullGC(Metadata GC Threashold) 元空间不足触发了GC
- FullGC(System.gc()) 手动调用触发GC
- FullGC(Ergonomics)
附录:JVM内存管理参数
DisableExplicitGC | 默认关闭 | 忽略来自System.gc()方法触发的垃圾收集 |
---|---|---|
ExplicitGCInvokesConcurrent | 默认关闭 | 当收到System.gc()方法提交的来机收集申请时,使用CMS收集器进行收集 |
UseSerialGC | Client模式的虚拟机默认开启,其他模式关闭 | 虚拟机运行在Client模式下的默认值,打开此开关后,使用Serial + Serial Old的收集器组合进行内存回收 |
UseParNewGC | 默认关闭 | 打开此开关后,使用ParNew + Serial Old的收集器组合进行内存回收 |
UseConcMarkSweepGC | 默认关闭 | 打开此开关后,使用ParNew + CMS + Serial Old的收集器组合进行内存回收.如果CMS收集器出现Concurrent Mode Failure,则Serial Old收集器将作为后备收集器 |
UseParallelGC | Server模式的虚拟机默认开启,其他模式关闭 | 虚拟机运行在Server模式下的默认值,打开此开关后,使用Parallel Scavenge + Serial Old的收集器组合进行内存回收 |
UseParallelOldGC | 默认关闭 | 打开此开关后,使用Parallel Scavenge + Parallel Old的收集器组合进行内存回收 |
SurvivorRatio | 默认为8 | 新生代中Eden区域与Survivor区域的容量比 |
PretenureSizeThreshold | 无默认值 | 直接晋升到老年代的对象大小,设置这个参数后,大于这个参数的对象将直接在老年代分配 |
MaxTenuringThreshold | 默认值为15 | 晋升到老年代的对象年龄,每个对象在坚持过一次Minor GC之后,年龄就+1,当超过这个参数值时就进入老年代 |
UseAdaptiveSizePolicy | 默认开启 | 动态调整java堆中各个区域的大小及进入老年代的年龄 |
HandlePromotionFailure | jdk1.5及以前是默认关闭,jdk1.6默认开启 | 是否允许分配担保失败,即老年代的剩余空间不足以应付新生代的整个Eden和Survivor区的所有对象都存活的极端情况 |
ParallelGCThreads | 少于或等于8个CPU时默认值为CPU数量值,多于8个CPU时比CPU数量值小 | 设置并行GC时进行内存回收的线程数 |
GCTimeRatio | 默认值99 | GC时间占总时间的比率.仅在使用Parallel Scavenge收集器时生效 |
MaxGCPauseMills | 无默认值 | 设置GC最大停顿时间.仅在使用Parallel Scavenge收集器时生效 |
CMSInitiatingOccupancyFraction | 默认值68 | 设置CMS收集器在老年代空间被使用多少后触发垃圾收集 |
UseCMSCompactAtFullCollection | 默认开启 | 设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理 |
CMSFullGCsBeforeCompaction | 无默认值 | 设置CMS收集器在进行若干次垃圾收集后再启动一次内存碎片整理 |
ScavengeBeforeFullGC | 默认开启 | 在Full GC发生之前触发一次Minor GC |
UseGCOverheadLimit | 默认开启 | 禁止GC过程无限制的执行,如果过于频繁,就直接发生OutOfMemory |
UseTLAB | Server模式默认开启 | 优先在本地线程缓冲区中分配对象,避免分配内存时的锁定过程 |
MaxHeapFreeRatio | 默认值70 | 当Xmx值比Xms值大时,堆可以动态收缩和扩展,这个参数控制当堆空闲大于指定比率时自动收缩 |
MinHeapFreeRatio | 默认值40 | 当Xmx值比Xms值大时,堆可以动态收缩和扩展,这个参数控制当堆空闲小于指定比率时自动收缩 |
MaxPermSize | 大部分情况下默认值是64MB | 永久代的最大值 |
即时编译参数 | ||
CompileThreshold | Client模式下默认值1500,Server模式下默认值10000 | 触发即时编译的阈值 |
OnStackReplacePercentage | Client模式下默认值933,Server模式下140 | OSR比率,它是OSR即时编译阈值计算公司的一个参数,用于代替BackEdgeThreshold参数控制回边计数器的实际溢出阈值 |
ReservedCodeCacheSize | 大部分情况下默认值32MB | 即时编译器编译的代码缓存使得最大值 |
类型加载参数 | ||
UseSplitVerifier | 默认开启 | 使用依赖StackMapTable信息的类型检查代替数据流分析,以加快字节码校验速度 |
FailOverToOldVerifier | 默认开启 | 当类型校验失败时,是否允许回到老的类型推到校验方式进行校验,如果开启则允许 |
RelaxAccessControlCheck | 默认开启 | 在校验阶段放松对类型访问性的限制 |
多线程相关参数 | ||
UseSpinning | Jdk1.6默认开启,Jdk1.5默认关闭 | 开启自旋锁以免线程频繁的挂起和唤醒 |
PreBolckSpin | 默认值10 | 使用自旋锁时默认的自旋次数 |
UseThreadPriorities | 默认开启 | 使用本地线程优先级 |
UseBiasedLocking | 默认开启 | 是否使用偏向锁,如果开启则使用 |
UseFastAccessorMethods | 默认开启 | 当频繁反射执行某个方法时,生成字节码来加快反射的执行速度 |
性能参数 | ||
AggressiveOpts | Jdk1.6默认开启,Jdk1.5默认关闭 | 使用激进的优化特征,这些特征一般是具备正面和负面双重影响的,需要根据具体应用特点分析才能判定是否对性能有好处 |
UseLargePage | 默认开启 | 如果可能,使用大内存分页,这项特性需要操作系统的支持 |
LargePageSizeInBytes | 默认值4MB | 使用指定大小的内存分页,这项特性需要操作系统的支持 |
StringCache | 默认开启 | 是否使用字符串缓存,开启则使用 |
调试参数 | ||
HeapDumpOnOutOfMemoryError | 默认关闭 | 在发生内存溢出异常时是否生成堆转储快照,关闭则不生成 |
OnOutOfMemoryError | 无默认值 | 当虚拟机抛出内存溢出异常时,执行指令的命令 |
OnError | 无默认值 | 当虚拟机抛出ERROR异常时,执行指令的命令 |
PrintClassHistogram | 默认关闭 | 使用[ctrl]-[break]快捷键输出类统计状态,相当于jmap-histo的功能 |
PrintConcurrentLocks | 默认关闭 | 打印J.U.C中的状态 |
PrintCommandLineFlags | 默认关闭 | 打印启动虚拟机时输入的非稳定参数 |
PrintFlagsFinal | ---- | 显示所有可设置的参数及它们的值(***从JDK 6 update 21开始才可以用) |
PrintFlagsInitial | ---- | 显示在处理参数之前所有可设置的参数及它们的值,然后直接退出程序 |
PrintCompilation | 默认关闭 | 打印方法即时编译信息 |
PrintGC | 默认关闭 | 打印GC信息 |
PrintGCDetails | 默认关闭 | 打印GC的详细信息 |
PrintGCTimeStamps | 默认关闭 | 打印GC停顿耗时 |
PrintTenuringDistribution | 默认关闭 | 打印GC后新生代各个年龄对象的大小 |
TraceClassLoading | 默认关闭 | 打印类加载信息 |
TraceClassUnloading | 默认关闭 | 打印类卸载信息 |
PrintInlining | 默认关闭 | 打印方法内联信息 |
PrintCFGToFile | 默认关闭 | 将CFG图信息输出到文件,只有DEBUG版虚拟机才支持此参数 |
PrintIdealGraphFile | 默认关闭 | 将Ideal图信息输出到文件,只有DEBUG版虚拟机才支持此参数 |
UnlockDiagnosticVMOptions | 默认关闭 | 让虚拟机进入诊断模式,一些参数(如PrintAssembly)需要在诊断模式中才能使用 |
PrintAssembly | 默认关闭 | 打印即时编译后的二进制信息 |