什么是垃圾回收机制?
垃圾回收的本质就是释放垃圾占用的空间,在Java中这个垃圾就是指:当程序创建对象,数组等引用类型实体时,系统会在堆内存中为之分配一块内存区,对象就保存在内存区中,当内存不再被任何引用变量引用时,这块内存就变成了“垃圾”,等待垃圾回收机制去进行回收。
垃圾回收GC(Garbage Collection)也算是Java里的一大特色,因为问到GC,就绕不开JVM调优问题,这是后话,先看两个问题:
1、什么时候回收?
由于程序无法精准控制垃圾回收的运行,则垃圾回收在合适的时候进行,当对象永久性失去了引用后,系统就会在合适的时间回收它所占的内存。
2、如何取消回收?
在垃圾回收机制回收任何对象之前,总会调用它的finalize()方法,该方法可能使该对象重新复活(使用一个引用变量重新去引用该对象),从而导致垃圾回收机制取消回收。
![P6程序员应掌握的Java垃圾回收机制常识,你掌握多少?](http://p2.ttnews.xyz/loading.gif)
那么如何初步判断对象是否可以被回收?
在Java中,要操作对象,就要通过引用来进行,于是可以通过引用计数来判断一个对象是否可以被回收。通常而言,如果如果一个对象没有任何引用与之关联,则说明该对象基本不太可能在其他地方被使用到,那么这个对象就成为可被回收的对象了,也就是引用计数法。来,看代码:
public class Main {
public static void main(String[] args) {
MyObject object1 = new MyObject();
MyObject object2 = new MyObject();
object1.object = object2;
object2.object = object1;
object1 = null;
object2 = null;
}
}
class MyObject{
public Object object = null;
}
在什么情况下可以将对象判定为可回收对象?先说比较简单的三种:
1)显示地将某个引用赋值为null或者将已经指向某个对象的引用指向新的对象,比如下面的代码:
Object obj = new Object();
obj = null;
Object obj1 = new Object();
Object obj2 = new Object();
obj1 = obj2;
2)局部引用所指向的对象,比如下面这段代码:
void fun() {
.....
for(int i=0;i<10;i++) {
Object obj = new Object();
System.out.println(obj.getClass());
}
}
循环每执行完一次,生成的Object对象都会成为可回收的对象。
3)只有弱引用与其关联的对象,比如:
WeakReference<string> wr = new WeakReference<string>(new String("world"));/<string>/<string>
![P6程序员应掌握的Java垃圾回收机制常识,你掌握多少?](http://p2.ttnews.xyz/loading.gif)
如何强制回收垃圾?
当一个对象失去引用后,系统何时调用它的finalize()方法对它进行资源清理,何时它可以变成不可达状态,系统何时回收它占有的内存,对于程序完全透明。程序只能控制一个对象不再被任何引用变量引用,不能控制它何时被回收。
程序可以强制系统进行垃圾回收——这种强制只是通知系统进行垃圾回收,但系统是否进行垃圾回收依然不能确定。大部分时候,程序强制垃圾回收后总是有一些效果。
强制系统垃圾回收有如下两个方法:
调用System类的gc()静态方法:System.gc()
调用Runtime对象的gc()实例方法:Runtime.getRuntime().gc()
强制垃圾回收代码:
public class GcTest
{
public static void main(String[] args)
{
for (int i = 0 ; i < 1; i++)
{
new GcTest();
// 下面两行代码的作用完全相同,强制系统进行垃圾回收
// System.gc();
Runtime.getRuntime().gc();
}
}
public void finalize()
{
System.out.println("系统正在清理GcTest对象的资源...");
}
}
常见的GC算法有哪些?
标记-清除算法(Mark-Sweep)
最基础的GC算法,将需要进行回收的对象做标记,之后扫描,有标记的进行回收,这样就产生两个步骤:标记和清除。这个算法效率不高,而且在清理完成后会产生内存碎片,这样,如果有大对象需要连续的内存空间时,还需要进行碎片整理,所以,此算法需要改进。
复制算法(Copying)
前面我们谈过,新生代内存分为了三份,Eden区和2块Survivor区,一般Sun的JVM会将Eden区和Survivor区的比例调为8:1,保证有一块Survivor区是空闲的,这样,在垃圾回收的时候,将不需要进行回收的对象放在空闲的Survivor区,然后将Eden区和第一块Survivor区进行完全清理,这样有一个问题,就是如果第二块Survivor区的空间不够大怎么办?这个时候,就需要当Survivor区不够用的时候,暂时借持久代的内存用一下。此算法适用于新生代。
标记-整理(或叫压缩)算法(Mark-Compact)
和标记-清楚算法前半段一样,只是在标记了不需要进行回收的对象后,将标记过的对象移动到一起,使得内存连续,这样,只要将标记边界以外的内存清理就行了。此算法适用于持久代。
由于篇幅限制,就先给大家分享这么多关于Java垃圾回收机制的常见面试问题,如果你需要一些这方面的视频教程,关注转发并私信我“编程”即可获取,希望对大家的面试有所帮助。
閱讀更多 編程進階007 的文章