1、所谓垃圾回收机制:是JVM对堆内存区域的回收
2、怎样确定一个线程是否可以被回收:
方法一:计数法:在内存中用计数器记录该对象被引用的次数,当被引用时就+1,对象释放就-1,当计数器中数为0时说明是该回收的线程了。但是这种方法有漏洞:当A 和B两个对象相互引用形成循环,那么计数器中的数就一直是1,这样就不会被察觉得到。这样就用到了
第二种方法:
方法二:根搜索:就是找这个对象有没有路径可以到达根,如果有则不回收,如果没有那么进行回收。
如下图:对象D访问不到根对象,所以就会被回收
3、 在根搜索所得到的回收对象前有一个复活环节:有且仅有一次复活机会,如果不能复活,那么就会永远死去,呵呵。实现他的函数是finalize(),我们要重写一下:以下对象会被认为是root对象:
- 被启动类(bootstrap加载器)加载的类和创建的对象
- jvm运行时方法区类静态变量(static)引用的对象
- jvm运行时方法去常量池引用的对象
- jvm当前运行线程中的虚拟机栈变量表引用的对象
- 本地方法栈中(jni)引用的对象
package deadToLive;
/**
* Created by Administrator on 2015/11/3 0003.
*/
public class DeadToAlive {
private static DeadToAlive deadToAlive;
public void finalize() throws Throwable{
try {
super.finalize();
DeadToAlive.deadToAlive=this;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
DeadToAlive.deadToAlive=new DeadToAlive();
DeadToAlive.deadToAlive=null;
System.gc();
Thread.sleep(500);
if(deadToAlive!=null)
System.out.println("Alive");
else
System.out.println("Dead");
DeadToAlive.deadToAlive=null;
System.gc();
Thread.sleep(500);
if(deadToAlive!=null)
System.out.println("Alive");
else
System.out.println("Dead");
}
}
首先标记一次,将其放在F-queue队列中,等待执行finalize()函数,执行后GC进行二次标记,而此时赴会的不会被标记,只有在执行完finalize()后仍然dead的那么就直接进行回收了。
4、垃圾回收的策略:
(1)标记--清除:直接将内存中二次标记的的线程进行消除,这样简便但是会造成碎片的产生,内存的浪费。
(2)标记--复制:将堆分成8:1:1的1个Eden和2个survivor构成新生代。
每次将Eden和Survivor中存活的对象
复制到另一块空闲的Survivor中。这三块区域并不是堆的全部,而是构成了新生代。
从下图可以看到这三块区域如何配合完成GC的,具体的对象空间分配以及晋升请
![](https://img-my.csdn.net/uploads/201209/02/1346555212_7344.png)
为什么不是全部呢?如果回收时,空闲的那一小块Survivor不够用了怎么办?这就是
老年代的用处。当不够用时,这些对象将直接通过
分配担保机制进入老年代。那么
老年代也使用标记-复制策略吧?当然不行!(
老年代是使用标记--整理策略
)老年代中的对象可不像新生代中的,
每次回收都会清除掉大部分。如果贸然采用复制的策略,老年代的回收效率可想而知。
(3)标记--整理:将所有Alive下来的线程都整理到一块去,这样解决了(1)的局限性,并且满足老年代的特点。
![](https://img-my.csdn.net/uploads/201209/02/1346555246_8570.png)
(1)新生代的GC:
serial:单线程,当他进行回收时,其它工作线程必须暂停
parNew:多线程
parallel scavenge:吞吐量优先
(2)老年代的GC:
serial old:单线程
parallel old:多线程
CMS:是基于标记--清除
6、什么情况下进行GC:
(1)新生代回收:
Minor GC(新生代回收)的触发条件比较简单,
Eden空间不足就开始进行Minor GC
回收新生代。
(2)老年代回收:
(1)老年代空间不足
(2)PermSpace空间不足
(3)统计得到的Minor GC晋升到老年代的平均大小大于老年代的剩余空间
这里注意一点:
PermSpace并不等同于方法区,只不过是Hotspot JVM用PermSpace来
实现方法区而已
,有些虚拟机没有PermSpace而用其他机制来实现方法区。
7、要回收对象空间分配和晋升:
对象优先分到新生代的Eden中
大对象分配到老年代中
新生代中的对象每熬过一次Minor GC就会+1岁,当为15岁时就会进入老年代
资源来源:http://blog.csdn.net/dc_726/article/details/7934101