olegst
olegst

Reputation: 1267

HashMap.remove and garbage collection

If I add objects to HashMap and then just call remove method when they are no longer needed, does it guarantee the resources they take will be released (given there are no other references to them)?

Upvotes: 3

Views: 7960

Answers (6)

Vids
Vids

Reputation: 1

I place objects in a HashMap and then remove them.

The class of the objects placed in the HashMap:

public class ObjectTestsub {

    String name;
    
    public ObjectTestsub(String name) {
        this.name = name;
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("ObjectTestsub: " + name + " is garbage collected");
    }
}

The main:

public class ObjectTest {

    HashMap<String, ObjectTestsub> map;

    public static void main(String[] args) {

        var map = new HashMap<String, ObjectTestsub>();

        for (int i = 0; i < 1000000; i++) {
            map.put("Obj" + i, new ObjectTestsub("first " + i));
            map.remove("Obj" + i);
        }
    }
}

The output:

....
ObjectTestsub: first 822685 is garbage collected
ObjectTestsub: first 822684 is garbage collected
ObjectTestsub: first 822683 is garbage collected
ObjectTestsub: first 822682 is garbage collected
....
ObjectTestsub: first 822677 is garbage collected
ObjectTestsub: first 822676 is garbage collected
ObjectTestsub: first 822675 is garbage collected
ObjectTestsub: first 822674 is garbage collected

The quantity of the objects "destroyed" is matter of the Java garbage collector. What is relevant here is that some objects are collected (so have been released). Everything goes fine.

Now I change the code:

public class ObjectTest {

    HashMap<String, ObjectTestsub> map;

    public static void main(String[] args) {

        var map = new HashMap<String, ObjectTestsub>();

        for (int i = 0; i < 1000000; i++) {
            map.put("Obj" + i, new ObjectTestsub("first " + i));
        }
        System.out.println("first part has DONE!       size: " + map.size());
        
        for (int i = 0; i < 1000000; i++) {
            map.remove("Obj" + i);
        }
        System.out.println("second part has DONE!       size: " + map.size());
    }
}

Here the output:

first part has DONE!       size: 1000000
second part has DONE!       size: 0

There is no message from the "destructor" of the "ObjectTestsub" objects anymore. It looks like they haven't been released...

Where is the trick? :/

Upvotes: -1

ivan.mylyanyk
ivan.mylyanyk

Reputation: 2101

No, as you may have a reference to that object from somewhere else.

Simple example:

Map < int, Object > map = new HashMap < int, Object > ();
CustomObject x = new CustomObject();
map.put(1, x);
map.remove(1);
//you still have access to x

Upvotes: 1

SubOptimal
SubOptimal

Reputation: 22963

The HashMap entries are stored in an array. If you remove an entry the related array position will be null. So the hashMap has not anymore a reference to the removed value object.

Then the normal rules for the garbage collection will be applied for the value object.

Simple code to verify.

public class REPL7 {

    public static void main(String[] args) throws Exception {
        Map<String, Foo> map = new HashMap();
        map.put("one", new Foo("foo one"));
        map.put("two", new Foo("foo two"));

        // make the backing array accessible
        Field field = map.getClass().getDeclaredField("table");
        field.setAccessible(true);
        Object[] obj = (Object[]) field.get(map);

        // two references to Foo objects will be shown            
        System.out.println("obj = " + Arrays.toString(obj));

        map.remove("one");

        // only one reference to a Foo object will eb shown
        System.out.println("obj = " + Arrays.toString(obj));
    }
}

class Foo {
    String marker;

    Foo(String marker) {
        this.marker = marker;
    }

    @Override
    public String toString() {
        return "Foo{" + marker + '}';
    }
}

Upvotes: 2

Ammy
Ammy

Reputation: 379

Garbage collection always done in heap memory where all objects initialize. When you call remove method in HashMap it only removes the id and value from it not the object you created.

Upvotes: 1

SchonWieder
SchonWieder

Reputation: 213

If the Map is the only thing with a reference to the Object and you remove the Object reference from the Map then yes, the Object is no longer referenced from anywhere and will be eligible for GC. As always, the resources it took are guaranteed to be released, but there is no guarantee when that will happen.

Upvotes: 0

Jordi Castilla
Jordi Castilla

Reputation: 26961

If you are sure of:

there are no other references to them

Yes, they're candidates to GC, what does not mean they will be inmediatelly recollected!!.

You can do with:

System.gc();

But is not a good idea. For further info check this and this questions.

Upvotes: 4

Related Questions