http://blog.csdn.net/alivetime/article/details/6895537
GC日志图解
运行时内存以及垃圾收集器
http://www.cnblogs.com/God-froest/p/jvm_1_3.html
// JVM笔记 http://www.javaranger.com/archives/655#more-655
// http://sishuok.com/forum/blogCategory/showByCategory.html?categories_id=25&user_id=247// http://blog.csdn.net/alivetime/article/details/6895537
// 【很重要】 JVM汇总 http://blog.csdn.net/jimmy1980/article/details/4968308
关键词:
内存不足GC:Minor GC,Major GC。
调优参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails
1.对象优先在Eden分配
2.大对象直接进入到老年代
-XX:PretenureSizeThreshold=3145728 //3M 直接进入到老年代的大对象,不分配在Eden空间。
避免新生代的大对象,使用复制算法,效率低的问题。
3.长期存活的对象将进入老年代
-XX:MaxTenuringThreshold=1
* -XX:MaxTenuringThreshold=1
* 当(在Survivor中的)对象被GC一次,就年龄增加为1,之后累加
* 当达到1时,就晋升到老生代。
4.动态对象年龄判定
虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。
5. 担保机制
空间分配担保:
每次Minor GC执行完以后,虚拟机会检查之前晋升到老年代的平均大小是否大于老年代的剩余空间大小,
如果大于,则发起一次Full/Major GC,
如果小于,则查看HandlePromotionFailure值是否允许担保失败,
如果允许,那只会进行一次Minor GC。
如果不允许失败,那么也要改为进行一次Full/Major GC
/***
* 很重要!!!
* 这段代码总共发生了2次GC,alloc4 = new byte[4 * _1M];
* 这个时候发生一次,因为Eden区内存不够用了,这次内存回收会把Eden区的所有的存活的对象转移到老年代,并把alloc4存放入Eden区,
* 此时Eden区4M,Survivor区0M,老年区6M;
* 第二次GC发生在最后一个alloc1 = new byte[6 * _1M],Eden区占有4M,不够用,
* 所以Eden区的存活对象要进入老年代,老年代之前晋升了6M,大于剩余空间4M,所以此时发生一次Full/Major GC,
* 因为alloc2,alloc3,alloc4设置为null,所以在这次Full/Major GC中被清理了,老年代只剩下2M,新的alloc1=6M进入Eden区。
从日志中可以看到我的分析结果:Eden区占用了77%,大约6M,tenured generation占21%大约2M,
为什么不是精确的相等,我的理解是垃圾收集器线程运行本身会耗费一定量的资源,所以不会严格的相等。
*/
private static int _1M = 1024 * 1024;
/**
* -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
*
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
byte[] alloc1, alloc2, alloc3, alloc4, alloc5;
alloc1 = new byte[2 * _1M];
alloc2 = new byte[2 * _1M];
alloc3 = new byte[2 * _1M];
alloc4 = new byte[4 * _1M];// 发生Minor GC
alloc2 = null;
alloc3 = null;
alloc4 = null;
alloc5 = new byte[6 * _1M];
}