ChatGPT解决这个技术问题 Extra ChatGPT

What's the difference between SoftReference and WeakReference in Java?

What's the difference between java.lang.ref.WeakReference and java.lang.ref.SoftReference ?

SoftReferences are type of (not really but for discussion sake) WeakReferences which are usually collected when JVM thinks it is out of memory.
@AjeetGanga, Loose weak refs are always collected whenever the GC runs. See stackoverflow.com/a/46291143/632951

i
itsmysterybox

From Understanding Weak References, by Ethan Nicholas:

Weak references A weak reference, simply put, is a reference that isn't strong enough to force an object to remain in memory. Weak references allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself. You create a weak reference like this: WeakReference weakWidget = new WeakReference(widget); and then elsewhere in the code you can use weakWidget.get() to get the actual Widget object. Of course the weak reference isn't strong enough to prevent garbage collection, so you may find (if there are no strong references to the widget) that weakWidget.get() suddenly starts returning null. ... Soft references A soft reference is exactly like a weak reference, except that it is less eager to throw away the object to which it refers. An object which is only weakly reachable (the strongest references to it are WeakReferences) will be discarded at the next garbage collection cycle, but an object which is softly reachable will generally stick around for a while. SoftReferences aren't required to behave any differently than WeakReferences, but in practice softly reachable objects are generally retained as long as memory is in plentiful supply. This makes them an excellent foundation for a cache, such as the image cache described above, since you can let the garbage collector worry about both how reachable the objects are (a strongly reachable object will never be removed from the cache) and how badly it needs the memory they are consuming.

And Peter Kessler added in a comment:

The Sun JRE does treat SoftReferences differently from WeakReferences. We attempt to hold on to object referenced by a SoftReference if there isn't pressure on the available memory. One detail: the policy for the "-client" and "-server" JRE's are different: the -client JRE tries to keep your footprint small by preferring to clear SoftReferences rather than expand the heap, whereas the -server JRE tries to keep your performance high by preferring to expand the heap (if possible) rather than clear SoftReferences. One size does not fit all.


Post no more available, you can find it on wayback machine: web.archive.org/web/20061130103858/http://weblogs.java.net/blog/…
this time, the archive is no longer available
Great explanation. This question can come up in Java related job interviews.
d
driekken

Weak references are collected eagerly. If GC finds that an object is weakly reachable (reachable only through weak references), it'll clear the weak references to that object immediately. As such, they're good for keeping a reference to an object for which your program also keeps (strongly referenced) "associated information" somewere, like cached reflection information about a class, or a wrapper for an object, etc. Anything that makes no sense to keep after the object it is associated with is GC-ed. When the weak reference gets cleared, it gets enqueued in a reference queue that your code polls somewhere, and it discards the associated objects as well. That is, you keep extra information about an object, but that information is not needed once the object it refers to goes away. Actually, in certain situations you can even subclass WeakReference and keep the associated extra information about the object in the fields of the WeakReference subclass. Another typical use of WeakReference is in conjunction with Maps for keeping canonical instances.

SoftReferences on the other hand are good for caching external, recreatable resources as the GC typically delays clearing them. It is guaranteed though that all SoftReferences will get cleared before OutOfMemoryError is thrown, so they theoretically can't cause an OOME[*].

Typical use case example is keeping a parsed form of a contents from a file. You'd implement a system where you'd load a file, parse it, and keep a SoftReference to the root object of the parsed representation. Next time you need the file, you'll try to retrieve it through the SoftReference. If you can retrieve it, you spared yourself another load/parse, and if the GC cleared it in the meantime, you reload it. That way, you utilize free memory for performance optimization, but don't risk an OOME.

Now for the [*]. Keeping a SoftReference can't cause an OOME in itself. If on the other hand you mistakenly use SoftReference for a task a WeakReference is meant to be used (namely, you keep information associated with an Object somehow strongly referenced, and discard it when the Reference object gets cleared), you can run into OOME as your code that polls the ReferenceQueue and discards the associated objects might happen to not run in a timely fashion.

So, the decision depends on usage - if you're caching information that is expensive to construct, but nonetheless reconstructible from other data, use soft references - if you're keeping a reference to a canonical instance of some data, or you want to have a reference to an object without "owning" it (thus preventing it from being GC'd), use a weak reference.


Particularly useful for the explanation of when weak objects would be used.
A key point about the proper use of a WeakReference is that in places where one should be using it, the fact that one may remain valid for a little while after the reference goes out of scope may be tolerable, but is not desirable.
I'm struggling to understand what is the use of WeakHashMap if it always produces weak reference to its key value object?
@Pacerier: The author of that post is simply wrong. He neglects some other usage scenarios like event subscription, his second point is nonsensical, and his third point assumes that a programmer can do things that may not be possible. His first point is reasonable, but ties in directly with what I said. If code will frequently have to build and compare large immutable objects, for example, the building part will often be cheaper if code creates new objects without regard for whether they already exist, but a comparison between an object and itself (identical references) will be...
...much cheaper than a comparison between two different immutable objects that hold the same data. If code needs an object that matches an existing object, using a reference to the existing object (instead of a new one) will be helpful if those objects will end up being compared. If the object exists in the interned cache and nowhere else, however, returning a reference to that would be more expensive than, and offer no advantages over, creating a new object and returning a reference to that.
P
Premraj

In Java; order from strongest to weakest, there are: Strong, Soft, Weak and Phantom

A Strong reference is a normal reference that protects the referred object from collection by GC. i.e. Never garbage collects.

A Soft reference is eligible for collection by garbage collector, but probably won't be collected until its memory is needed. i.e. garbage collects before OutOfMemoryError.

A Weak reference is a reference that does not protect a referenced object from collection by GC. i.e. garbage collects when no Strong or Soft refs.

A Phantom reference is a reference to an object is phantomly referenced after it has been finalized, but before its allocated memory has been reclaimed.

Source

Analogy: Assume a JVM is a kingdom, Object is a king of the kingdom, and GC is an attacker of the kingdom who tries to kill the king(object).

When King is Strong, GC can not kill him.

When King is Soft, GC attacks him but King rule the kingdom with protection until resource are available.

When King is Weak, GC attacks him but rule the kingdom without protection.

When king is Phantom, GC already killed him but king is available via his soul.


Soft reference ... until memory is available doesn't make sense. Do you mean is eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another use?
yes, garbage collector won't collect the reference until the memory is available.
I like simple explained stuff, without too much bla bla bla +1 from me !
Excellent summary with innovative example
P
Premraj

Weak Reference http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html

Principle: weak reference is related to garbage collection. Normally, object having one or more reference will not be eligible for garbage collection.
The above principle is not applicable when it is weak reference. If an object has only weak reference with other objects, then its ready for garbage collection.

Let's look at the below example: We have an Map with Objects where Key is reference a object.

import java.util.HashMap;   
public class Test {

    public static void main(String args[]) {
        HashMap<Employee, EmployeeVal> aMap = new 
                       HashMap<Employee, EmployeeVal>();

        Employee emp = new Employee("Vinoth");
        EmployeeVal val = new EmployeeVal("Programmer");

        aMap.put(emp, val);

        emp = null;

        System.gc();
        System.out.println("Size of Map" + aMap.size());

    }
}

Now, during the execution of the program we have made emp = null. The Map holding the key makes no sense here as it is null. In the above situation, the object is not garbage collected.

WeakHashMap

WeakHashMap is one where the entries (key-to-value mappings) will be removed when it is no longer possible to retrieve them from the Map.

Let me show the above example same with WeakHashMap

import java.util.WeakHashMap;

public class Test {

    public static void main(String args[]) {
        WeakHashMap<Employee, EmployeeVal> aMap = 
                    new WeakHashMap<Employee, EmployeeVal>();

        Employee emp = new Employee("Vinoth");
        EmployeeVal val = new EmployeeVal("Programmer");

        aMap.put(emp, val);

        emp = null;

        System.gc();
        int count = 0;
        while (0 != aMap.size()) {
            ++count;
            System.gc();
        }
        System.out.println("Took " + count
                + " calls to System.gc() to result in weakHashMap size of : "
                + aMap.size());
    }
}

Output: Took 20 calls to System.gc() to result in aMap size of : 0.

WeakHashMap has only weak references to the keys, not strong references like other Map classes. There are situations which you have to take care when the value or key is strongly referenced though you have used WeakHashMap. This can avoided by wrapping the object in a WeakReference.

import java.lang.ref.WeakReference;
import java.util.HashMap;

public class Test {

    public static void main(String args[]) {
        HashMap<Employee, EmployeeVal> map = 
                      new HashMap<Employee, EmployeeVal>();
        WeakReference<HashMap<Employee, EmployeeVal>> aMap = 
                       new WeakReference<HashMap<Employee, EmployeeVal>>(
                map);

        map = null;

        while (null != aMap.get()) {
            aMap.get().put(new Employee("Vinoth"),
                    new EmployeeVal("Programmer"));
            System.out.println("Size of aMap " + aMap.get().size());
            System.gc();
        }
        System.out.println("Its garbage collected");
    }
}

Soft References.

Soft Reference is slightly stronger that weak reference. Soft reference allows for garbage collection, but begs the garbage collector to clear it only if there is no other option.

The garbage collector does not aggressively collect softly reachable objects the way it does with weakly reachable ones -- instead it only collects softly reachable objects if it really "needs" the memory. Soft references are a way of saying to the garbage collector, "As long as memory isn't too tight, I'd like to keep this object around. But if memory gets really tight, go ahead and collect it and I'll deal with that." The garbage collector is required to clear all soft references before it can throw OutOfMemoryError.


You may get a NullPointerException in aMap.get().put(...).
Your first HashMap example looks wrong. When you do "aMap.put(emp, val);" both 'emp' and 'val' are strong references. Internally, a new variable is created to hold 'emp' and 'val' so when you do "emp = null;" you are just nullifying the "emp" variable, but not the variable internally to the hash map (which is still holding the original Employee object). Therefore the hash map will still hold a strong reference to 'emp' regardless of what you do with the 'emp' variable outside.
@Tiago. No. Presumably by "first example" you are referring to the WeakHashMap example (since that is the first one that is demonstrating Weak behavior). Look at doc for "WeakHashMap": "An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. " The entire point of using WeakHashMap is that you don't have to declare/pass-in a WeakReference; the WeakHashMap does that for you, internally. docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html
Took 0 calls to System.gc() to result in weakHashMap size of : 0 is the output of your second program ?
For another example of WeakHashMap in action, with example app showing how entries are removed only after garbage-collection executes, see my Answer to the Question, Is WeakHashMap ever-growing, or does it clear out the garbage keys?.
i
itsmysterybox

The only real difference between a soft reference and a weak reference is that

the garbage collector uses algorithms to decide whether or not to reclaim a softly reachable object, but always reclaims a weakly reachable object.


@ATorras, Samir. I expanded on this answer here: stackoverflow.com/a/46291143/632951
T
Tom Hawtin - tackline

SoftReference is designed for caches. When it is found that a WeakReference references an otherwise unreachable object, then it will get cleared immediately. SoftReference may be left as is. Typically there is some algorithm relating to the amount of free memory and the time last used to determine whether it should be cleared. The current Sun algorithm is to clear the reference if it has not been used in as many seconds as there are megabytes of memory free on the Java heap (configurable, server HotSpot checks against maximum possible heap as set by -Xmx). SoftReferences will be cleared before OutOfMemoryError is thrown, unless otherwise reachable.


But in Android it isn't advised for caches developer.android.com/reference/java/lang/ref/…
@DoctororDrive tbf the question was about java, not dalvik! :-P
@YaroslavMytkalyk, Frankly, if Android wants to rewrite the behavior of a class, it should use its own namespace, not java.lang. Such abuse of synonyms is doing no one any good.
L
Lavish Kothari

This article can be super helpful to understand strong, soft, weak and phantom references.

To give you a summary,

If you only have weak references to an object (with no strong references), then the object will be reclaimed by GC in the very next GC cycle.

If you only have soft references to an object (with no strong references), then the object will be reclaimed by GC only when JVM runs out of memory.

So you can say that, strong references have ultimate power (can never be collected by GC)

Soft references are powerful than weak references (as they can escape GC cycle until JVM runs out of memory)

Weak references are even less powerful than soft references (as they cannot excape any GC cycle and will be reclaimed if object have no other strong reference).

Restaurant Analogy

Waiter - GC

You - Object in heap

Restaurant area/space - Heap space

New Customer - New object that wants table in restaurant

Now if you are a strong customer (analogous to strong reference), then even if a new customer comes in the restaurant or what so ever happnes, you will never leave your table (the memory area on heap). The waiter has no right to tell you (or even request you) to leave the restaurant.

If you are a soft customer (analogous to soft reference), then if a new customer comes in the restaurant, the waiter will not ask you to leave the table unless there is no other empty table left to accomodate the new customer. (In other words the waiter will ask you to leave the table only if a new customer steps in and there is no other table left for this new customer)

If you are a weak customer (analogous to weak reference), then waiter, at his will, can (at any point of time) ask you to leave the restaurant :P


A
Arsen Khachaturyan

The six types of object reachability states in Java:

Strongly reachable objects - GC will not collect (reclaim the memory occupied by) this kind of object. These are reachable via a root node or another strongly reachable object (i.e. via local variables, class variables, instance variables, etc.) Softly reachable objects - GC may attempt to collect this kind of object depending on memory contention. These are reachable from the root via one or more soft reference objects Weakly reachable objects - GC must collect this kind of object. These are reachable from the root via one or more weak reference objects Resurrect-able objects - GC is already in the process of collecting these objects. But they may go back to one of the states - Strong/Soft/Weak by the execution of some finalizer Phantomly reachable object - GC is already in the process of collecting these objects and has determined to not be resurrect-able by any finalizer (if it declares a finalize() method itself, then its finalizer will have been run). These are reachable from the root via one or more phantom reference objects Unreachable object - An object is neither strongly, softly, weakly, nor phantom reachable, and is not resurrectable. These objects are ready for reclamation

For more details: https://www.artima.com/insidejvm/ed2/gc16.html « collapse


Not a good description of phantom references. Also, you've listed the 4 types in a peculiar order. "phantom" is the weakest type, not the strongest type. The traditional order to list these is "strong, soft, weak, phantom". And I have no idea where you got the notion that phantom objects are used for caching mechanisms. AFAIK, they are a temporary state seen only by the GC, not something that an ordinary programmer would work with.
@ToolmakerSteve and all - Apologies for couple of things 1. the wrong explanation of Phantom references in the previous version of my answer, and 2. Delay in correcting the errors. Now the answer has been improved by correcting the errors
P
Pacerier

The Only Real Difference

Per the doc, loose WeakReferences must be cleared by a running GC.

Per the doc, loose SoftReferences must be cleared before OOM is thrown.

That's the only real difference. Everything else is not part of the contract. (I'll assume the latest docs are contractual.)

SoftReferences are useful. Memory-sensitive caches use SoftReferences, not WeakReferences.

proper

weak_ref.get()

null

As for incorrect use of WeakReference, the list is endless:

a lousy hack to implement priority-2 softreference such that you don't have to write one, yet it doesn't work as expected because the cache would be cleared on every GC run, even when there is spare memory. See https://stackoverflow.com/a/3243242/632951 for phails. (Besides, what if you need more than 2 levels of cache priority? You'd still gotta need a real library for it.)

a lousy hack to associate data with an object of an existing class, yet it creates a memory leak (OutOfMemoryError) when your GC decides to take a break after your weakreferences are created. Besides, it's beyond ugly: A better approach is to use tuples.

a lousy hack to associate data with an object of an existing class, where the class has the nerve to make itself non-subclassable, and is used in an existing function code which you need to call. In such a case, the proper solution is to either edit the class and make it subclassable, or edit the function and make it take an interface instead of a class, or use an alternative function.


What about a cache where the key type's equals() is just object identity? Soft references seem like a waste there, because once a key object is no longer strongly reachable, no one will ever look up that mapping again.
I disagree. Use WeakReference when you don't want to influence GC in anyway (You might want to save an object reference and then check later if it still exists, without any preference that it does). Use SoftReference if you want to influence the GC to try and keep the object (i.e. when you would prefer that the GC would keep it).
A good example where to use WeakReference is in Android's AsyncTask - to keep an instance of the context. That way if the context dies (if activity - screen rotation, etc.), the AsyncTask won't have any strong reference to it, and so it can be garbage collected. Check youtu.be/…
R
Ravi K

To give an in-action memory usage aspect, I did an experiment with Strong, Soft, Weak & Phantom references under heavy load with heavy objects by retaining them till end of program. Then monitored heap usage & GC behavior. These metrics may vary case by case basis but surely gives high level understanding. Below are findings.

Heap & GC Behavior under heavy load

Strong/Hard Reference - As program continued, JVM couldn't collect retained strong referenced object. Eventually ended up in "java.lang.OutOfMemoryError: Java heap space"

Soft Reference - As program continued, heap usage kept growing, but OLD gen GC happened hen it was nearing max heap. GC started bit later in time after starting program.

Weak Reference - As program started, objects started finalizing & getting collected almost immediately. Mostly objects got collected in young generation garbage collection.

Phantom Reference - Similar to weak reference, phantom referenced objects also started getting finalized & garbage collected immediately. There were no old generation GC & all objects were getting collected in young generation garbage collection itself.

You can get more in depth graphs, stats, observations for this experiment here.


F
Fai Lau

One should be aware that a weakly referenced object will only get collected when it has ONLY weak reference(s). If it has so much as one strong reference, it does not get collected no matter how many weak references it has.


This is common sense... same goes for softref and phantomref.
A
Artem Petrov

WeakReference: objects that are only weakly referenced are collected at every GC cycle (minor or full).

SoftReference: when objects that are only softly referenced are collected depends on:

-XX:SoftRefLRUPolicyMSPerMB=N flag (default value is 1000, aka 1 second) Amount of free memory in the heap. Example: heap has 10MB of free space (after full GC); -XX:SoftRefLRUPolicyMSPerMB=1000 Then object which is referenced only by SoftReference will be collected if last time when it was accessed is greater then 10 seconds.