简体   繁体   中英

Java Garbage Collecting Reference Classes

I'm testing how gc works with the classes in java.lang.ref package, just for study :)

The following is my code.

public static void main(String [] args) {

    int mb = 1024*1024;

    //Getting the runtime reference from system
    Runtime runtime = Runtime.getRuntime();

    System.out.println("##### Heap utilization statistics [MB] #####");
    ArrayList<Object> sb = new ArrayList<Object>();
    for(int i =0; i < 5000000; i++){
        sb.add(new Object());
        if( i % 1000 == 0) {
            System.out.println(i);
        }
    }

    SoftReference<ArrayList> wr = new SoftReference<ArrayList>(sb);

    // System.gc()

    //Print used memory
    System.out.println("Used Memory:"
        + (runtime.totalMemory() - runtime.freeMemory()) / mb);

    //Print free memory
    System.out.println("Free Memory:"
        + runtime.freeMemory() / mb);

    //Print total available memory
    System.out.println("Total Memory:" + runtime.totalMemory() / mb);

    //Print Maximum available memory
    System.out.println("Max Memory:" + runtime.maxMemory() / mb);
}

It results:

Used Memory:95,
Free Memory:28,
Total Memory:123,
Max Memory:247

And I undid comment on "System.gc()", and reran the code, the result was

Used Memory:1,
Free Memory:122,
Total Memory:123,
Max Memory:247

Yeah, firstly, the instance of ArrayList was collected. As I know, Instances referenced only by SoftReference is softreachable, so collected when GC is really needed because of lack of left heap space. The left space of first result of the code was about 150(free mem 28 + left max mem 124). I don't understand why the instance of ArrayList was collected.

And secondly, I ran the code with modifying:

sb.add(new Object()); -> sb.add(new StringBuffer(i));

and It resulted:

Used Memory:245,
Free Memory:2,
Total Memory:247,
Max Memory:247

Why is this different??

And lastly, I ran the code again with modifying: from

SoftReference<ArrayList> wr = new SoftReference<ArrayList>(sb);

to

WeakReference<ArrayList> wr = new WeakReference<ArrayList>(sb);

It resulted:

Used Memory:245,
Free Memory:2,
Total Memory:247,
Max Memory:247

I had guessed the instances of ArrayList were collected because the instances were referenced only by WeakReferece, so these were weakreachable. But they were not collected.

I now assume that my understanding about the way of Reference's work was incorrect.

Please anyone let me know why.

Thx ^^

The embedded question is easiest to answer: if you replace new Object() with new StringBuffer(i) with an increasing i , you are creating StringBuffer instances with an increasing capacity, so it shouldn't come at a surprise that these objects require much more memory than a stateless Object instance.

The main question is not so easy to answer as you are presenting us a hard-to-reproduce result and in-between turn to a much-easier-to-reproduce result which suggest that either, you have changed more in your code than you have said or there were subtle changes in your testing environment in-between. In principle, both results are possible, but completely unrelated to the change you have made.

First of all, by the time you are invoking System.gc() you are holding a strong reference to the ArrayList in a local variable, so whether the additional reference is weak or soft, is completely irrelevant. In most setups and test runs, you will experience the ArrayList and the contained objects still occupying memory.

But this is not the end of the story. As discussed in “finalize() called on strongly reachable object in Java 8” , an object can get collected even if a strong reference is held, if the JVM can prove that this reference will not used. As further discussed, whether this will happen merely depends on the optimization state of the JVM and the executed code, so it's rather unlikely to happen with your example program consisting of a sole main method which usually runs in the interpreter, but it's not impossible.

But if this happens, this logic applies to all unused references within your method, which includes the reference to the SoftReference resp. WeakReference instance. If that Reference object itself gets collected, it's semantic against the referent will again be irrelevant. Then, the ArrayList , the contained objects and the reference object are collected together.

If you set the sb variable to null explicitly before invoking System.gc() and invoke get() on the reference object after it, you may experience different results, but keep in mind, that System.gc() still is only a hint to the JVM and may be ignored, thus having no effect at all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM