P6程序员应掌握的Java垃圾回收机制常识,你掌握多少?

什么是垃圾回收机制?

垃圾回收的本质就是释放垃圾占用的空间,在Java中这个垃圾就是指:当程序创建对象,数组等引用类型实体时,系统会在堆内存中为之分配一块内存区,对象就保存在内存区中,当内存不再被任何引用变量引用时,这块内存就变成了“垃圾”,等待垃圾回收机制去进行回收。

垃圾回收GC(Garbage Collection)也算是Java里的一大特色,因为问到GC,就绕不开JVM调优问题,这是后话,先看两个问题:

1、什么时候回收?

由于程序无法精准控制垃圾回收的运行,则垃圾回收在合适的时候进行,当对象永久性失去了引用后,系统就会在合适的时间回收它所占的内存。

2、如何取消回收?

在垃圾回收机制回收任何对象之前,总会调用它的finalize()方法,该方法可能使该对象重新复活(使用一个引用变量重新去引用该对象),从而导致垃圾回收机制取消回收。

P6程序员应掌握的Java垃圾回收机制常识,你掌握多少?


那么如何初步判断对象是否可以被回收?

在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垃圾回收机制常识,你掌握多少?


如何强制回收垃圾?

当一个对象失去引用后,系统何时调用它的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垃圾回收机制的常见面试问题,如果你需要一些这方面的视频教程,关注转发并私信我“编程”即可获取,希望对大家的面试有所帮助。


分享到:


相關文章: