Java的引用和垃圾回收机制

Collaborating with the Java Memory Manager
By Brian Gilstrap, Principal Software Engineer, Object    Computing, Inc. (OCI)

   
Java developers are all familiar with the Java garbage    collector, which eliminates the need to explicitly deallocate objects.     However, few know that there is a package in Java 2[TM] (JDK 1.2 and later) which    allows them to coordinate their activities with the garbage collector. This    package java.lang.ref, provides a number of classes to allow developers    some interaction with garbage collector.  To understand how these classes    are useful, we must first understand the different types of references.

Types of Object References
   All developers use object references when programming.  For example, the    following line of Java code declares a reference to a String and makes it refer    to a string object with contents "hello":

String aHelloString = "hello"

The variable aHelloString is an object reference.  In    order to distinguish these garden variety object references from the other kinds    of references we will be discussing, Java calls this kind of reference a strong        reference. This is because the String object referred to by aHelloString    is held onto "strongly", meaning it can't be garbage collected as long as    it is referred to in this manner.

In addition to normal, strong references, there are three    other kinds of references that Java 2[TM] provides.  They provide    increasingly "weaker" kinds of references, meaning that each successive type    of reference places fewer restrictions on the garbage collector. These three    types of references are:
    

  • soft references        (java.lang.ref.SoftReference)    

  • weak references        (java.lang.ref.WeakReference)    

  • phantom references        (java.lang.ref.PhantomReference)


   All of these reference types share certain common characteristics:
    

  • They all refer to a single object, called the        referent (see Figure 1 below)    

  • They are created with a constructor that        includes a reference to the referent, and will either refer to it or to no        object at all.    

  • There is a get() method which can be used to        get back a strong reference to the referent (if that reference hasn't been        cleared)    

  • The garbage collector will clear the reference        at its discretion when certain conditions are met (the conditions for each        kind of reference are discussed below)


   These other kinds of references are created by creating an instance of one of    the reference classes in the java.lang.ref package (SoftReference,    WeakReference, or PhantomReference). There is also a java.lang.ref.Reference    class but it is an abstract base class for the other three and cannot be    instantiated.

Let�s look at an example,. The following line of code    corresponds to Figure 1:

Reference aRef = new SoftReference( new    String( �foo� ) );
    
   
    
                                        
   
   Figure 1


   While we created a SoftReference in the code, we could have created a    WeakReference or a PhantomReference and achieved essentially the same state of    affairs.

By looking at Figure 1, we can see that these new kinds of    reference objects add overhead in terms of space (there is another Java object    on the heap, the reference object), and they also cost us some time (the garbage    collector interacts with these references in certain ways, which takes    time).  This leads us to a question: what features do these references        offer that would make it worth the time and space to use them?  To    understand this, we need to look at each kind of reference.

Soft References
   Soft references are good for providing caches of objects which can be garbage    collected when the Java Virtual Machine (JVM) is running low on memory.  In    particular, the JVM guarantees a couple of useful things:
    

  1. It will not garbage collect an object as long as        there are normal, strong references to it    

  2. It will not throw an OutOfMemoryError until it has        "cleaned up" all softly reachable objects (objects not reachable by        strong references but reachable through one or more soft references).


   This allows us to use soft references to refer to objects that we could afford    to have garbage collected, but which it is convenient to have around until    memory becomes tight.  Obviously, this means our program has to be able to    live without these objects or be able to recreate them.  But we can let the    garbage collector decide when to collect these objects, continuing the Java goal    of letting the programmer avoid explicit memory management.

There is no specific timeframe after an object "goes soft"    (becomes reachable through soft references but not through strong references)    when the garbage collector will collect the object, but the documentation    encourages JVM implementors to prefer collecting older objects and to delay    collection as long as is feasible.
    

Weak References
   Weak references are good for providing "canonicalizing mappings".     These are mappings from some unique identifier to an object.  For example,    imagine we have permanent storage (a file, database, etc.) containing a large    number of Employee objects, and that we only work with a subset of them at any    given time (perhaps there are too many to fit in a running JVM on the machines    we have, and we only need to work with a small number of them at any given    time).  Assume that we uniquely identify employees by an employee    number.  We could use weak references to refer to all employee objects    currently in the JVM and provide a Map (or HashTable) which maps from the    employee number to a weak reference to the corresponding Employee object (see    Figure 2).
   
    
    
   
   Figure 2


   When using this sort of approach, we have a "canonical" mapping between the    employee number and the Employee object, meaning there is a one-to-one    correspondence between employee numbers as keys in the map, and Employee objects    which have that employee number.

We would not want to prevent an Employee object from being    garbage collected if no other part of the program is using that object, since we    could always retrieve the object from permanent storage.  In addition, we    want to avoid using a soft reference because this puts pressure on the garbage    collector (since it has to wait until running out of memory to reclaim the    objects).  If we use weak references, we give the garbage collector greater    freedom to collect an Employee object more quickly.

This approach allows us to work with a subset of a very large    collection of objects (all employees) in a Java program running on a machine    with much less memory than we would need if we tried to read in all Employee    objects.  If we didn�t have weak references, we would have to work around    the garbage collector to determine when to "free" a given Employee object,    removing all the benefits of the garbage collector and automatic memory    management.

Phantom References
   Phantom references are a bit different than the previous two kinds of    references.  It turns out that you can never get back the referent of a    PhantomReference once you have created it (calling the get() method always    returns null).  Yet the PhantomReference still holds onto a reference to    its referent.  Why is this?

Phantom references are designed to allow for "pre-mortem"    cleanup.  This means that you can learn about an object which is going to    be garbage collected just before it actually gets collected and clean up    resources it is using.  This is particularly useful if you have several    objects collaborating together, and you need to do the cleanup only when all of    the objects are no longer using that shared resource. You can keep track of the    shared resource and when the last object becomes phantomly reachable do the    actual cleanup.

This still leaves one piece of the puzzle missing: how do    we know when the object has become phantomly reachable? This leads us to the    one remaining class in the java.lang.ref package: ReferenceQueue.  When    creating a reference object (phantom, weak, or soft), you can specify a    reference queue to associate with the reference object.  In addition to the    behavior already described, the garbage collector will place such reference    objects onto the specified ReferenceQueue when it takes action on that reference    object.

This allows us to read the references off the queue and know    that the garbage collector has done its work with that reference.  In the    case of a PhantomReference, we can take note of the references which have become    phantom and when the reference to the last object using the shared resource    "goes phantom", we can clean up that shared resource.  We can choose to    dedicate a thread to reading entries off a ReferenceQueue, or we can poll it at    strategic points in the code.

Summary
   The new kinds of references provided by the java.lang.ref package enable    developers to build smarter, more efficient programs.  And while we can�t    create fundamentally new kinds of references, we can subclass the concrete    reference classes (SoftReference, WeakReference, and PhantomReference) to add    features (this is common with PhantomReference as a way to keep track of the    shared resource to be cleaned up).

These classes are not used frequently, but when they are    needed they are invaluable.  By making them a standard part of Java 2[TM],    programmers get a consistent means to build more robust software without    resorting to platform/JVM-specific approaches.


    ​由上文可以简单总结如下:

    ​强引用:即是大家都最熟悉的引用,不必多说

    ​软引用:当内存紧张时JVM才会回收软引用指向的资源;

    ​弱引用:当JVM要回收该资源时,JVM将不再犹豫(即不管内存是否紧张);

    ​虚引用:引用已经处于回收并重置内存空间的边缘,程序猿可以利用该引用对马上“死亡”的对象做最后操作;


    ​各引用存在的作用:

    ​软引用上面并没有提到其用处;     弱引用可以用来做“canonicalizing mappings”,即适合用做缓存;    虚引用适合于用来判断共享内存是否适合回收——即程序猿可以得到即将回收对象的信息,并判断他是否适合回收;

    ​说到底,之所以会有那么多中引用的出现,一是为了JVM内部对回收对象的管理和判断,二是为了方便程序猿和JVM之间的相互通信,便于程序猿更好的监控和管理项目,使运行性能更佳。

    ​至于更深一步的理解,以后再在这里续上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值