Java 垃圾回收机制

原创 2016年08月29日 11:08:40

垃圾回收

垃圾回收回调方法:

  • finalize()函数是在JVM回收内存时执行的,但JVM并不保证在回收内存时一定会调用finalize()。

JVM的垃圾回收机制:

  • 在内存充足的情况下,显式调用System.gc()(system.gc调用仅仅是建议虚拟机进行回收,并不一定马上会进行gc)
  • 在内存不足的情况下,垃圾回收将自动运行

对象状态

  • 可达状态:
    有一个以上的引用变量引用此对象

  • 可恢复状态:
    如果程序中某个对象不再有任何的引用变量引用它,它将先进入可恢复状态,系统的垃圾回收机制准备回收该对象的所占用的内存,在回收之前,系统会调用finalize()方法进行资源清理,如果资源整理后重新让一个以上引用变量引用该对象,则这个对象会再次变为可达状态,否则就会进入不可达状态。

  • 不可达状态:
    当对象的所有关联都被切断,且系统调用finalize()方法进行资源清理后依旧没有使该对象变为可达状态,则这个对象将永久性失去引用并且变成不可达状态,系统才会真正的去回收该对象所占用的资源。

引用

级别: 强引用 > 软引用 > 弱引用 > 虚引用

StrongReference

默认引用实现,当没有任何对象指向它时,GC执行后将会被回收

Food food = new Food();
food = null;

WeakReference

所引用的对象在JVM内不再有强引用时,GC执行后将会被回收

处理过程:

  • WeakReference对象的referent域被设置为null,从而使该对象不再引用heap对象。
  • WeakReference引用过的heap对象被声明为finalizable。
  • 同时或者一段时间后WeakReference对象被添加到它的ReferenceQueue(如果ReferenceQueue存在的话)。

对于软引用和弱引用,入队和finalize方法的执行是没有固定顺序的

 Food food = new Food();
 WeakReference<Food> weakFood = new      WeakReference<Food>(food);
 food = null;

使用:随时取得某对象的信息(不影响此对象的垃圾收集)

A obj = new A();
WeakReference wr = new WeakReference(obj);
obj = null;
//等待一段时间,obj对象就会被垃圾回收
...
if (wr.get()==null) {
  System.out.println("obj 已经被清除了 ");} else {
  System.out.println("obj 尚未被清除,其信息是 "+obj.toString());
}

SoftReference

类似WeakReference,但SoftReference会尽可能长的保留引用直到JVM内存不足时才会被回收, 适合缓存应用

处理过程同WeakReference

Food food = new Food();
SoftReference<Food> softFood = new  SoftReference<Food>(food);
food = null;
// JVM OutOfMemory

使用:简单对象cache

A obj = new A();
SoftRefenrence sr = new SoftReference(obj);
//引用时
if(sr!=null){
   obj = sr.get();
}else{
  obj = new A();
  sr = new SoftReference(obj);
}

PhantomReference

跟踪referent何时被enqueue到ReferenceQueue中,它唯一的目的就是对象被回收时能收到一个通知,用于追踪对象被垃圾回收的状态,需要和引用队列ReferenceQueue类联合使用。

不建议使用,有潜在的内存泄露风险,因为JVM不会自动帮助我们释放,我们必须要保证它指向的堆对象是不可达的

虚引用带来的内存泄露风险参考:java中虚引用PhantomReference与弱引用WeakReference(软引用SoftReference)的差别

软引用和弱引用差别不大,JVM都是先将其referent字段设置成null,之后将软引用或弱引用,加入到关联的引用队列中。我们可以认为JVM先回收堆对象占用的内存,然后才将软引用或弱引用加入到引用队列。

而虚引用则不同,JVM不会自动将虚引用的referent字段设置成null,而是先保留堆对象的内存空间,直接将PhantomReference加入到关联的引用队列,也就是说如果我们不手动调用PhantomReference.clear(),虚引用指向的堆对象内存是不会被释放的。

处理过程:

  • 不把referent设置为null.
  • PhantomReference引用过的heap对象处理到finalized状态,即调用了finalize()方法.
  • heap对象被释放之前把PhantomRefrence对象添加到它的ReferenceQueue中.

摘录部分盖楼评论:
我觉得其实是这样,其实GC做的工作分成是两部分,第一部分是将对象从finalizable状态到finalized状态,这只是完成了资源的释放;第二部分是reclaimed对象占用的内存。其实所有在ref中的三种reference的referent的对象的reclaimed都只有在相应reference对象的clear方法调用之后,才能进行,所以,GC只是保证weakreference、softreference的clear方法被GC自动调用,并被加到referencequeue中,但是phantomreference对象在被加入到referencequeue中之前对象就已经被GC finalied(如果定义了finalize方法的话,我所指的finalized是指调用了finalize方法)了,只是还没有进行第二步reclaimed,因为phantomreference对象的clear方法还没有被调用,所以不能进行reclaimed。

  Food food = new Food();
  PhantomReference<Food> phantomFood = new PhantomReference<Food>(food, new ReferenceQueue<Food>()); 
  food = null;

使用:

  • Object的finalize方法在回收之前调用,若在finalize方法内创建此类的强引用会导致对象无法回收,可能引发JVM OutOfMemory
  • PhantomReference在finalize方法执行后进行回收,避免上述问题

��参考网页关于虚引用PhantomReference

@SuppressWarnings("static-access")
public static void main(String[] args) throws Exception {
    String abc = new String("abc");
    System.out.println(abc.getClass() + "@" + abc.hashCode());
    final ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();
    new Thread() {
        public void run() {
            while (isRun) {
                Object obj = referenceQueue.poll();
                if (obj != null) {
                    try {
                        Field rereferent = Reference.class
                                .getDeclaredField("referent");
                        rereferent.setAccessible(true);
                        Object result = rereferent.get(obj);
                        System.out.println("gc will collect:"
                                + result.getClass() + "@"
                                + result.hashCode() + "\t"
                                + (String) result);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }.start();
    PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,
            referenceQueue);
    abc = null;
    Thread.currentThread().sleep(3000);
    System.gc();
    Thread.currentThread().sleep(3000);
    isRun = false;
}

总结

  • 强引用指向的对象如果被引用,发生GC时是不会被回收的,除非该对象没有被引用
  • 软引用在内存非常紧张的时候会被回收(无引用),其他时候不会被回收,所以在使用之前要判断是否为null从而判断他是否已经被回收了
  • 弱引用和虚引用指向的对象(无引用)在发生GC时一定会被回收
  • 通过虚引用得不到引用的对象实例,虚引用的get()方法永远返回null

参考

Java的内存回收机制
[深入理解ReferenceQueue GC finalize Reference](深入理解ReferenceQueue GC finalize Reference)
Java中三个引用类SoftReference 、 WeakReference 和 PhantomReference的区别
Java引用
引用
Java幽灵引用的作用

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

java垃圾回收机制

  • 2016-06-19 07:57
  • 14KB
  • 下载

Java垃圾回收机制详解

  • 2011-10-03 23:03
  • 33KB
  • 下载

Java垃圾回收机制

说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来。在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理。顾名思...

Java垃圾回收机制详解

  • 2011-11-19 14:33
  • 199KB
  • 下载

Java垃圾回收机制

  • 2013-06-17 01:07
  • 62KB
  • 下载

java垃圾回收机制

Java虚拟机的内存区域中,程序计数器、虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭;栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构...

【java】垃圾回收机制

什么是Java垃圾回收器 Java垃圾回收器是Java虚拟机(JVM)的三个重要模块(另外两个是解释器和多线程机制)之一,为应用程序提供内存的自动分配(Memory Allocation)、自动回收...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)