GC & Reference

Java对象的生命周期(Life Cycle)

  • 在VM运行时间中,对象的生命周期分为以下几个阶段:

    创建(Create)阶段:创建对象。

    应用(Use)阶段:至少维护着对象的一个Strong Reference(普通引用),默认全是强引用除非显式声明其他引用(SoftReference,WeakReference,PhantomReference)。

    不可视(Invisible)阶段:Stack中的强引用已经无效(值为null),便于GC发现后及时回收对象。

    不可达(Unreachable)阶段:VM管理的对象引用根集合(Root Set)中再也找不到对象的强引用,预备被回收的对象,但是不能直接被GC。

    可收集(Collectable)、结束(Finalized)、清除(Clear)阶段:对象可能被回收也可能被重用。


Java Garbage Collector(以下简称GC) 简述

  • 一切皆对象,对象存于内存中(Java内存模型:对象存于无序的Heap中,对象的引用存于Stack中,在运行时通过引用访问对象),当对象被创建时,GC就开始监控对象的地址 、大小以及使用状态。GC机制具有特定的回收算法,一般使用有向图的方式来记录队列中的所有对象,GC遍历Root Set中的引用(Set<Reference>)发现对象不可达时回收对象(常见方式:将引用置为null)。当执行System.gc()时,GC不一定会对内存中的对象进行回收,GC的时机取决于VM和系统。

  • VM一般启动一个或多个线程来执行GC,也就会占用一定的内存以及CPU。设计GC时,需要在WaitTime以及回收率之间权衡。如果GC运行时间过长,会导致明显的停顿(阻塞),如果运行时间太短,则会导致较多对象没有回收。

  • 常见GC方式:

    增量式(Incremental)的GC:将一个长时间的中断分成许多小的中断(分治),减少对程序本身的影响,该方式整体性能没有明显的提高,但是减少了停顿感。

    引用计数法(Reference Counting Collector)

    Tracing算法(Tracing Collector)

    Compacting算法(Compacting Collector)

    Copying算法(Copying Collector)

    Generation算法(Generational Collector)

    Adaptive算法(Adaptive Collector)


java.lang.ref.Reference(以下简称reference)可以与GC进行特定的交互,从而提升内存的使用率。一般在嵌入式或者实时以及一些对内存要求严格的系统中比较有效。GC根据不同的state将reference入队或出队。按队列的方式,GC只需要检查下一个队列中的reference就可以确定如何处理当前实例。如果下一个为null,则当前为active,否则按正常处理。

ReferenceQueue(引用队列),当GC检测到适当的可达性改变后将已注册的reference添加到queue中。该类实现了入队enqueue)和出队(非阻塞的poll 和 阻塞的remove),内部持有一个reference,链表的结构由reference自身实现。

  • reference内部有四个可能的state:

    活动的(Active):GC根据创建reference实例时是否注册referencQueue特殊处理该实例,可能会将state变为pending或者inactive,如果有注册则会将instance添加到pending-reference列表中。

    将要发生的(Pending):Pending-reference list的一个元素(如果未注册不会进入该state),等待被reference-handler(thread)入队。

    入队的(Enqueued):ReferenceQueue队列中的一个元素(如果未注册不会进入该state),如果移出队列则变为inactive。

    闲置的(Inactive):不会做任何事情,如果state变为inactive则不会再改变。

Java对象有四种类型(以下只考虑当前类型):

  • Strong Reference(强引用),Java的默认引用实现没有实际的类型,强引用可以直接访问目标对象,当对象存在强引用时则永远不会被回收,可能导致内存泄露(OOM)。

  • String str = "ss";//将强引用str指向对象"ss"
    str = null; //释放强引用,GC回收
  • SoftReference(软引用),当内存不足时GC会释放软可及(softly reachable)对象,软引用一般用于实现内存敏感(memory-sensitive)的缓存。在VM抛出OOM之前,GC会释放所有的软可及对象,最大限度的使用内存。构造软引用时可以传入也可以不传ReferenceQueue(以下简称queue),当GC回收reference引用的目标对象(以下简称referent)后,回调reference的enqueue方法将其放入注册的queue中。

  • ReferenceQueue queue = new ReferenceQueue();
    Reference sr = new SoftReference("str", queue);//构造sr并注册queue
    sr.get();//返回"str"
    queue.poll();//只有当referent被回收后才会被入队,返回null
    System.gc();//内存足够,不会回收对象
    sr.get();//如果没有oom则返回"str"
    queue.poll();//只有当referent被回收后才会被入队,返回null
  • WeakReference(弱引用),无法阻止目标对象被结束(finalized),当对象只能弱可及(Weakly reachable)时,GC会回收referent,并将reference入队到注册的queue中,弱引用一般用于实现规范化映射(Canonicalizing Mapping)。WeakHashMap是HashMap的WeakReference实现,将Entry.Key封装到WeakReference中,当仅有Map持有弱引用时,则GC时被回收。

  • ReferenceQueue queue = new ReferenceQueue();
    Reference sr = new WeakReference("str", queue);//构造sr并注册queue
    sr.get();//返回"str"
    queue.poll();//只有当referent被回收后才会被入队,返回null
    System.gc();//不一定立即执行了GC,与平台、系统有关
    sr.get();//当只能弱可及时被回收,返回null
    queue.poll();//已经被回收,返回sr
  • PhantomReference(虚引用),当GC决定回收reference并执行finalize()后,GC将reference入队到注册的queue中(必须注册,只有该构造器),一般用于调度一些预清理操作,比finalize()更灵活(也可以作为GC标记)。为了确保referent回收后不会被恢复,get()始终返回null。SoftReference和WeakReference在referent被回收后,被GC入队到queue中并清除,而虚引用是在GC之前被入队,当目标对象的所有虚引用被清除或者不可及才会虚不可及。

  • ReferenceQueue queue = new ReferenceQueue();
    Reference sr = new PhantomReference("str", queue);//必须注册queue
    sr.get();//始终返回null

GC发现reference后,可能进行的处理:将referent置为null(不可及),将目标对象标记为finalizable,回收目标对象(执行finalize()并释放内存)将reference入队(soft/weak)


生命周期:Strong > Soft > Weak > Phantom,以下表格摘自

Type
Purpose Use When GCed Class
Strong Referenece An ordinary reference. Keeps objects alive as long as they are referenced Normal reference Any object not pointed to can be reclainmed Default
SoftReference Keeps objects alive provided there's enough memory
To keep objects alive even after clients have removed their references(memory-sensitive caches), in casse clients start asking for them again by key After a first gc pass, the JVM decides it still needs to reclaim more space java.lang.ref.SoftReference
WeakReference Keeps objects alive only while they're in use(reachable) by clients
Containers that automatically delete objects no longer in use After gc determines the objects is only weakly reachable

java.lang.ref.WeakReference

java.util.WeakHashMap

PhantomReference Lets you clean up after finalization but before the space is reclaimed Special clean up processing After finalization java.lang.ref.PhantomReference

推荐一篇写的很好的博文

你可能感兴趣的:(java,GC,reference)