How to free/GC HashMap<String,XYZ> on one shot (without iterating)? - java

I have some HashMap < String, XYZ > created having the key type as String and value type of some XYZ Class.Now for some condition check I want to free/ garbage collect the entire HashMap along with the individual objects of XYZ type that it holds. Is it possible to do it without iterating the hash map and setting each object to null ? I guess by setting only HashMap to null will not work. How do I ensure later that the collection of objects is garbage collected ?
If I do something like:
XYZ obj = new XYZ();
hm.put("<unique-id>",obj);
XYZ obj2 = new XYZ();
hm.put("<unique-id>",obj2);
.
.
.<more operations>
.
.
hm = null;
my code no longer reference either obj or obj2 after hm=null statement.
So can I be sure enough that the jvm will garbage collect obj and obj2 also shortly ?
Moreover in cases where hashmap is a huge collection, I dont want to use Iterator over HashMap to get and iterate over every object and set it to null.
Does just hm=null does the above stuffs of GCing the entire collection of objects + map for me ?

If an object isn't referenced anymore, you can be sure that the object is garbage collected properly. That means, if you set the hash map to null and you know that all the items within the map arn't referenced by other objects, then they are garbage collected. In case you want to call the gcc manually keep in mind that the decision whether the gcc process is executed or not is ultimately made by the JVM!

Related

filling HashMap within loop

a big doubt! I read that HashMap takes references of objects and doesn't copy values to store data. So if I have something like
HashMap<Integer, Double> map = HashMap<Integer, Double>();
for(int i = 0; i < 100; i++ ) {
Integer key = Integer(i);
Double value = Double(i*2.0);
map.put(key, value);
}
What is the result of
map.get(10);
? Keys and values are created within the for loop so I suppose that they are deleted at the end of for statement and put(10) give something like null. But I think it's a very annoying behaviour because I can't fill a HashMap with a straighforward for loop... I'm wrong?
I'm assuming you meant to ask what the result of map.get(10) is, since map.put(10) is not valid. map.get(10) would return the Double whose value is 20.0.
Since the map variable is declared outside the for loop, the values you put in the map remain there after the end of the for loop. The keys and values are not deleted at the end of the for loop because the map variable holds references to them.
First of all, in Java, all objects are accessed by reference - there is nothing special about the HashMap here.
Second, all objects are kept in memory until the Garbage collector (GC) decides to destroy them. The GC may destroy objects as soon as they are no longer referenced anywhere - it may not destroy them if they are still referenced.
In your example :
After the loop, the object referenced by map holds references to the same objects that were referenced by keyand value : those objects cannot be destroyed.
If, at a later point, you no longer hold any reference to the HashMap object, it may be destroyed by the GC, and the GC may also decide to destroy the key and the value, if they were only referenced by the Hashmap. Note that there is no guarantee given as to when garbage collection will occur: it won't necessarily happen immediately.
You can't do map.put(10), because HashMap doesn't have a method with a compatible signature. The only put method that exists for HashMap expects two parameters.
edit: Since the op corrected map.put(10) to map.get(10): it will return a reference to the same object that was briefly referenced by the variable value during the "i=10" iteration of the loop.
The key are hold by refrences as (almost)all objects in Java; java won't delete an object which is strongly referenced by another object.
object created in the loop will only be collected if no other object references them after the loop
since you put them into an hashmap, java will keep them around
note also that put(10, ...) actually is put(new Integer(10), ...) thanks to autoboxing

Is this java Object eligible for garbage collection in List

What I am asking might be a stupid question so please pardon me for that.
So it goes like this :
List<Boss> bossList = new ArrayList<Boss>();
Boss b = null;
for(Employee e : List<Employee> myList){
b = new Boss();
b.setEmployee(e);
bossList.add(b);
b = null;
}
So in above scenario, I am creating lot of Boss objects and then de-referencing them(I know I don't need to write "b = null", but i did it for clarity of my question). In normal scenario, I would have marked them to garbage collection, by doeing this, but because in this scenario, I am adding those Boss objects in List collection, are they marked for GC or not? If not then why? And how does List collection work internally to hold references for each Object added, so as to avoid garbage collection?
[EDIT]
The scope of question is only limited to the individual Boss objects created in for loop, considering that this method returns the reference of the List to the outside world.
The Boss objects will not be collected by the GarbageCollector because they are still referenced in the code block that you are posted. bossList is an ArrayList which has an internal array of Object thus holding references to those objects which are added to it.
I such a situation not only the references by you are considered but all referneces in all objects involved.
EDIT: Since you are returning the List in your code the objects will not be marked for garbage collection until the list is no longer referenced in your program.
ArrayList has Object[] elementData internally. When you added b to bossList ArrayList assigned elementData[0] = b. So when you assigned null to b the instance of Boss is still referenced from elementData[0] and cannot be GCed. But since ArrayList instance is referenced only from method's variable after the method returns both ArrayList and Boss instances will be eligible for GC.
Here's what really happens with your code :
Since java is pass by reference, whenever you add b to bossList, bossList starts referencing the memory location which b is pointing to. So when b nullified only link from b to the reference is broken. Thus keeping the object accessible through bossList.

Java collections and memory use

I have a question on Java memory use. It’s for my edification and anyone else who searches and finds this later! For the purpose of the question, please assume, this is a single method and nothing goes out of scope... during my question ;-)
I have created 5 new objects with a single property called ‘name’ of type String.
I create an ArrayList and add the 5 objects to the ArrayList. I then create a HashMap and iterate through the previously created ArrayList, adding the objects to the HashMap.
Q1. When I add the objects from the ArrayList, to the HashMap, I assume I am just creating another collection of ‘pointers’, since I’m not using the ‘new’ keyword. Therefore no new memory is consumed, except for the HashMap itself (the objects are not duplicated).
Q2. If I change the value of ‘name’, in an object in the HashMap, would the same change be seen, if I were to iterate over the ArrayList, after making the change.
I appreciate a ‘sanity check’ on my understanding.
Q1: The HashMap is created and the references to the objects are created. So memory is consumed, but references aren't terribly big, but can make a difference if the number of references is huge.
Q2: Edit: Yes, the name field would change. Better still, write a small program to check it out.
A1 : Yes, other than the references and HashMap, nothing new will be created. (Assuming you are not creating a new set of keys for for the HashMap)
A2 : Yes, the change will reflect on the ArrayList.
To answer your questions.
1.) When you add objects to a HashMap the objects are not duplicated. Internally though the map will create new objects to maintain its inner structure. The inner structure of a map consists of HashMap.Entry objects that contain a linked list with all values that map to the same hash code. Thus whenever you add objects to a map one or more internal objects are created.
2.) I assume you stored the objects in the HashMap using their name as key. In this case chaning the name of an object will update the object (no matter whether it's being accessed through the list or the map, it's always the same object) but not the mapping in the map. In the map the object will still be store under its old name!
Map map = new HashMap();
Foo f = new Foo();
f.setName("A");
map.put(f.getName(),f);
f.getName(); // => "A"
map.get("A"); // => f
f.setName("B");
f.getName(); // => "B"
map.get("B"); // => null
map.get("A"); // => f

How HashMap handles the updated <key,value>,if value itself is a Hashmap?

when we put a <key,value> in a HashMap,if the key is already present in the HashMap then the value gets replaced. But if for a key the value is itself a HashMap then would it get replaced with the HashMap?
Yes, it would be replaced. Remember that a Map only stores references to other objects.
You put a reference to a HashMap in a map, and the map keeps a reference to this HashMap.
If you put a reference to another HashMap using the same key, the reference to the first put HashMap is replaced by the reference to the new HashMap. The type of the object doesn't matter. It always works the same way.
If I understand what you're asking, you want to know if what you just said will cause a memory leak (please update your question if this isn't what you're asking).
If you do:
Map<?, ?> m = new HashMap<Object, Object>();
m.put(m, m);
Then m will ultimately only contain a reference to itself. Because of how Java's GC works via an object reference graph, and because they use an algorithm which tracks visited nodes during a GC sweep, if nothing maintains a reference to m, then m will be garbage collected, despite containing a reference to itself. Circular references are perfectly handled in the Java GC.
If m is placed into a field (i.e., not a local variable declared inside a method) then it's a different story.
If m is placed in a static field, then there will always be a reference to it from a GC root, which means it won't be reclaimed. Note: nothing strongly referenced to from a static field will ever be garbage collected.
If m is placed in a member field (non-static), then the map won't be garbage collected until the object that contains it is garbage collected.
If there are multiple fields that refer to m, then m won't be garbage collected until all those references are either a) part of an object that can be garbage collected or b) are set to null or some other value to no longer refer to m.
TL;DR the garbage collector handles circular object references just fine.
Sidenote: Please update your question with information, don't just add it as comments to your question or others' answers.
The wording in your question is a bit opaque, but a HashMap<HashMap, Object> is perfectly valid (if somewhat strange). In that case, if:
HashMap map = new HashMap<HashMap<String, String>, String>();
HashMap a = new HashMap<String, String>();
HashMap b = new HashMap<String, String>(); //a.equals(b) == true
map.put(a, "foo"); //map.get(a) would now return "foo"
map.put(b, "bar"); //original entry is replaced, map.get(a) would now return "bar"

How does object reference and cloning works in java

Below is the code
ArrayList arList = someMethod();// returning ArrayList with customDO objects
Now somewhere in different class I am getting data from this arList
CustomDo custDO= (CustomDO)arList.get(0);
Will the arList be alive as long as custDO is alive ? If yes, will below piece of code help
CustomDO custDO = ((CustomDO)arList.get(0)).cloneMe();
// where cloneMe has defintion as return ((CustomDO)super.clone());
// CustomDo implements Cloneable
Is there a better way to keep a copy of only the first element of arList and discard the list so that it can be collected by garbage collector ?
Is there a better to keep a copy of only the first element of arList and discard the list so that it can be collected by garbage collector ?
You don't have to make a copy of the list element. As long as you have another reference to it, it will not be garbage-collected, even if the list you got it from is. And the list will be garbage-collected as soon as you remove all references to it.
There is no need in Java to clone anything just to make sure that the object does not disappear. In Java a reference to an object is always valid. It cannot happen that the data for a live reference gets invalid.
You only want to make a copy (clone) if you are afraid that other people who reference the same object might change its contents (calling some setter on it) in ways that would cause trouble for you (or you want to have a private copy to change it without affecting others).
// reference to first object
CustomDO custDO = ((CustomDO)arList.get(0));
// let arList be garbage collected
arList = null;
Another thing you should know is that Collections clone() methods do a shallow (flat) copy. Sometimes you need to have deep copies (to allow modifing them independedly)
As long as you have access to CustomDO custDO object, it will not be garbage collected. The list can be garbage collected if there is no reference to it.
The ArrayList is an ordinary Object, and only references to this object will keep the list alive. Of course, as long as the list is alive, all its elements are also alive, but the converse does not hold.

Categories

Resources