How to garbage collect arrays of objects? - java

I'm working in huge program in java and now I'm trying to avoid loitering to improve it's memory usage, I instantiate some objects in the constructor, and keep instantiated till the end of the program but they are not always used. My question is specificly about garbage collecting arrays of Objects.
For example when the user presses a menu item a JDialog is invoked with lots of components in it, these components were instantiated at the moment that the program runs, but i want to instantiate them when necessary and free them when not.
For example:
JRadioButton Options = new JRadioButton[20];
for (int i = 0; i < 20; i++) {
Options[i] = new JRadioButton(Labels[i]);
}
If i want to free the arrays, what shoud i do?
This:
for (int i = 0; i < 20; i++) {
Options[i] = null;
Labels[i] = null;
}
Or simply:
Options = null;
Labels = null;
Thanks in advance

First, a Java object will be garbage collected only if it is not reachable (and it might have other references than your array). Then GC runs at nearly unpredictable times (so the memory might be freed much later).
Clearing the array's elements won't release the whole array, but could release each element (provided it becomes unreachable).
setting a variable to null might release the array (and of course all the elements).
But for a so small program, perhaps GC is never happening.
Read at least GC on wikipedia, and perhaps the GC handbook
Notice that the aliveness of some object is a whole program property (actually a whole process property: liveness of values is relevant in a particular execution, not in your source code). In other words, you could do Options = null; and still have the object in Options[24] reachable by some other reference path.

If Options holds the only reference to the array, either works to make the objects unreachable and release the objects to the garbage collector.
If something else is still referencing the array, it won't be released anyway, so the first option is the only one that will release the contents. Note that the first option will only release the contents, Options will still reference the actual Array unless you also set Options to null.

Doing
Options = null;
Labels = null;
should be enough to release those objects. There is no need to null the elements unless there is another reference to the array. However when there are other references to the array I do not think it is wise to null the elements. The other references are there for a reason. When they no longer need the array and its contents they should release their references.

Both will do but first one is recommended and then do second one.
Here is the source code from ArrayList clear() method
// Let gc do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
Another way to do same thing is
Arrays.fill(Options, null);
It does not do any thing different iterates and sets array elements to null.

Related

What is an Obsolete reference in java

I'm reading the Effective Java book and its saying that eliminating obsolete reference is one of best way to avoid memory leaks. according to the below program, by doing -> elements[size] = null; its eliminating obsolete references in that program.
My problem here what is the advantage of doing elements[size] = null;. Any other program can use that freed memory location? Or is it garbage collected?
According to my understanding the array is already allocated the memory for its size. Even we do elements[size] = null; anyone can't use that freed memory location until you do elements = null;. Please someone tell me what is advantage of doing elements[size] = null; here.
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
My problem here what is the advantage of doing elements[size] = null;.
Here obsolete references refer to object references not required any longer for the program.
You want that unnecessary objects to be free to consume only memory that your program need. Generally it is done for the good working of the current application.
Any other program can use that freed memory location?
Theoretically yes but it also depends on the JVM memory options used. You don't generally focus on it.
elements[size] = null and elements = null; don't have at all the same intention and the same effects.
In the context of the book, elements is a structural intern of a class.
The idea is that some elements of the array may be stale and not required any longer after some removal operations.
The first one (elements[size] = null) will make the object of the array element located at the size index to be eligible to be GC if no other objects reference .
But the second one (elements = null) is much more. It will make all elements of the array to be eligible to be GC if no other objects reference it.
There are two cases we have to distinguish:
The outer object is "teared down" somehow, so it closes any open resource and also "voluntarily" releases all objects it had referred to. This s simply the explicit way of telling the jvm that the corresponding refence is "gone". You make it easier for the gc to understand: the corresponding object is eligible for garbage collection. Of course, that only has that effect if there are no other references to the same object elsewhere. And beyond: doing so isn't really required, the jvm/gc must of course be able to detect any eligible object all by itself.
But nullifying makes sense for refences that exist for longer periods of time, pointing to different objects over that time span. Like a container, such as the stack class in the underlying example. A container must forget about objects it referenced to when they get "removed". Otherwise you create a memory leak!
What happens here?
Let's imagine, elements is a 20-elements Object array (elements = new Object[20];), and has been filled with 18 BigInteger instances, the remaining two places being null.
So the heap now contains 18 BigInteger instances and a 20-elements Object[] array. The garbage collector won't reclaim any of these instances, and that's okay as you'll most probably use them later (via the pop() method).
Now you call the pop() method to get the BigInteger most recently added to the array. Let's assume you just want to print it and then forget it, so in your overall application that number isn't needed any more, and you'd expect the garbage collector to reclaim it. But that won't happen unless you do the null assignment
elements[size] = null; // Eliminate obsolete reference
Why that?
As long as you store the reference to an object in some accessible place, the garbage collector believes that you'll still need the object later.
As long as elements[17] still refers to the BigInteger, it can potentially be accessed by your program, so it can't be reclaimed. If elements[17] points to null, the BigInteger that used to be there isn't accessible via elements any more and can be reclaimed by the garbage collector (if no other part of your code still uses it).
Conclusion
It's only worth thinking about "obsolete references" if you have a long-living storage structure that contains fat objects, and you can tell at some point in time that you won't need one of the stored objects any more. As you won't need this object any more, you can now re-assign the storage with null, and then the GC no longer believes you still need the object and is able to reclaim the storage space.

Which is faster, assigning variable directly or saving temp?

So I was reading the source code for java.util.LinkedList and I noticed a design choice that intrigued me. This is pulled from the .clear() method, where they iteratively go through every element in the linked list to remove them all from memory. My question is: why do they define the variable next instead of assigning x directly? Doesn't it take time to copy that element? At the very least, it temporarily takes more space while within that scope.
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
This is actually required. I'll go over the algorithm and code in order to show you why it is needed. Duly note that this question covers topics that are complex, so my answer is slightly formulated to make more sense to a beginner.
First, it's important to understand what is actually happening internally in the JVM when we use objects. In Java, an object (note not this does not include primitive types), is not actually passed around when we use them. Instead we are using references to objects, which are simply pointers to said objects. We do this so that we can not worry about memory allocation/de-allocation. Now in order to ensure an object is deleted when we no longer needs it, all objects have a count of how many times it is currently referenced within the current state of the program. Broadly speaking, when entering a scope that uses some object, the object's reference count is incremented entering the scope and decremented leaving the scope. Now when an object reaches 0 references, it means there is currently no part of our program that uses this object, therefore it can safely be deleted. This was just a quick summary of how the garbage collection works, but ultimately is more complex.
This method is iteratively going over each item in the list, and dereferencing each of the items that the current node, x, has a reference too. It is not saying that the objects item, prev, and next should be set to null, only the reference that x has to these objects. This is done so we know that when an object has 0 references, we can safely garbage collect this object. If we were to do as you proposed, such as here:
for (Node<E> x = first; x != null; ) {
x.item = null;
x.prev = null;
x = x.next;
}
Then the node x before we assigned it to x.next still maintains the reference to x.next, which is obviously unwanted because that object will continue to float around in memory even if the original x was deleted/goes out of scope.
To answer your question as to which is faster, it's insignificant. Yes, in that scope we save a few bytes for creating the variable next, but it's important to understand we're only creating a reference to it, we're not actually instantiating a new object, so there is practically no overhead (and optimized for in the JVM). This next object is just allocated temporarily on the stack, of which is overwritten on the next iteration of the loop, so it also does not create any concerns with memory use.

Overhead of short-lived references to existing objects in Java / Android

Recently I have come across an article about memory optimization in Android, but I think my question is more of a general Java type. I couldn't find any information on this, so I will be grateful if you could point me to a good resource to read.
The article I'm talking about can be found here.
My question relates to the following two snippets:
Non-optimal version:
List<Chunk> mTempChunks = new ArrayList<Chunk>();
for (int i = 0; i<10000; i++){
mTempChunks.add(new Chunk(i));
}
for (int i = 0; i<mTempChunks.size(); i++){
Chunk c = mTempChunks.get(i);
Log.d(TAG,"Chunk data: " + c.getValue());
}
Optimized version:
Chunk c;
int length = mTempChunks.size();
for (int i = 0; i<length; i++){
c = mTempChunks.get(i);
Log.d(TAG,"Chunk data: " + c.getValue());
}
The article also contains the following lines (related to the first snippet):
In the second loop of the code snippet above, we are creating a new chunk object for each iteration of the loop. So it will essentially create 10,000 objects of type ‘Chunk’ and occupy a lot of memory.
What I'm striving to understand is why a new object creation is mentioned, since I can only see creation of a reference to an already existing object on the heap. I know that a reference itself costs 4-8 bytes depending on a system, but they go out of scope very quickly in this case, and apart from this I don't see any additional overhead.
Maybe it's the creation of a reference to an existing object that is considered expensive when numerous?
Please tell me what I'm missing out here, and what is the real difference between the two snippets in terms of memory consumption.
Thank you.
There are two differences:
Non-optimal:
i < mTempChunks.size()
Chunk c = mTempChunks.get(i);
Optimal:
i < length
c = mTempChunks.get(i);
In the non-optimal code, the size() method is called for each iteration of the loop, and a new reference to a Chunk object is created. In the optimal code, the overhead of repeatedly calling size() is avoided, and the same reference is recycled.
However, the author of that article seems to be wrong in suggesting that 10000 temporary objects are created in the second non-optimal loop. Certainly, 10000 temp objects are created, but in the first, not the second loop, and there's no way to avoid that. In the second non-optimal loop, 10000 references are created. So in a way it is less than optimal, although the author mistakes the trees for the forest.
Further References:
1. Avoid Creating Unnecessary Objects.
2. Use Enhanced For Loop Syntax.
EDIT:
I have been accused of being a charlatan. For those who say that calling size() has no overhead, I can do no better than quoting the official docs:
3. Avoid Internal Getters/Setters.
EDIT 2:
In my answer, I initially made the mistake of saying that memory for references is allocated at compile-time on the stack. I realize now that that statement is wrong; that's actually the way things work in C++, not Java. The world of Java is C++ upside down: while memory for references is indeed allocated on the stack, in Java even that happens at runtime. Mind blown!
References:
1. Runtime vs compile time memory allocation in java.
2. Where is allocated variable reference, in stack or in the heap?.
3. The Structure of the Java Virtual Machine - Frames.

Java optimization to prevent heapspace out of memory

Ok, I have a problem in a particular situation that my program get the out of memory error from heap space.
Let's assume we have two ArrayList, the first one contains many T objects, the second one contains W object that are created from the T objects of first List.
And we cycle through it in this way (after the cycle the list :
public void funct(ArrayList<T> list)
{
ArrayList<W> list2 = new ArrayList<W>();
for (int i = 0 ; i < list.size() ; i++)
{
W temp = new W();
temp.set(list.get(i));
temp.saveToDB();
list2.add(temp);
}
// more code! from this point on the `list` is useless
}
My code is pretty similar to this one, but when list contains tons of objects I often get the heap space out of memory (during the for cycle), I'd like to solve this problem.
I do not know very well how the GC works in java, but surely in the previous example there are a lot of possible optimization.
Since the list is not used anymore after the for cycle I thought as first optimization to change from for loop to do loop and empty the list as we cycle through it:
public void funct(ArrayList<T> list)
{
ArrayList<W> list2 = new ArrayList<W>();
while (list.size() > 0)
{
W temp = new W();
temp.set(list.remove(0));
temp.saveToDB();
list2.add(temp);
}
// more code! from this point on the `list` is useless
}
Is this modification useful?
How can I do a better optimization to the above code? and how can I prevent heap space out of memory error? (increasing the XMX and XMS value is not a possibility).
You can try to set the -XX:MaxNewSize=40% of you Xmx AND -XX:NewSize=40% of you Xmx
This params will speedup the GC calls, because your creation rate is high.
For more help : check here
It really depends on many things. How big are the W and T objects?
One optimization you could surely do is ArrayList list2 = new ArrayList(list.size());
This way your listarray does not need to adjust its size many times.
That will not do much difference tough. The real problem is probably the size and number of your W and T objects. Have you thought of using different data structures to manage a smaller portion of objects at time?
If you did some memory profiling, you would have discovered that the largest source of heap exhaustion are the W instances, which you retain by adding them to list2. The ArrayList itself adds a very small overhead per object contained (just 4 bytes if properly pre-sized, worst case 8 bytes), so even if you retain list, this cannot matter much.
You will not be able to lessen the heap pressure without changing your approach towards the non-retention of each and every W instance you have created in your loop.
You continue to reference all the items from the original list :
temp.set(list.get(i)) // you probably store somewhere the passed reference
If the T object has a big size and you don't need all of its fields, try to use a projection of it.
temp.set( extractWhatINeed( list.get(i) ) )
This will involve creating a new class with fewer fields than T (the return type of the extract method).
Now, when you don't reference the original items, they are eligible for GC (when the list itself will not be referenced anymore).

Why does repeating setLabel() in SWING cause out of memory?

The class variables are like this:
Button[] tab_but = new Button[440];
static int ii;
After initializing tab_but, I'm testing the following job.
for (int j = 0; j < 9999; j++) {
String newLabel = String.valueOf(ii);
for (int i = 0; i < 440; i++) {
tab_but[i].setLabel(newLabel);
}
ii += 1;
}
And it gets 'out of memory' finally.
As I profiled it, Object [] allocation was increasing rapidly with running it.
I think I did only replacing the label, so the previous label object(String) should be cleaned. right?
Why does that kind of memory leak occur?
Please advise and thanks.
I strongly suspect there's something you haven't shown us here. 10000 strings is nothing in terms of memory. If each string is, say, 64 bytes (and that's almost certainly larger than reality) then those 10000 strings take up 640K. I'm assuming you have rather more memory than that, and you haven't set the maximum heap size to something tiny?
Could you provide a short but complete program which demonstrates the problem here?
I wonder whether it's not the strings which are causing the problem, but the fact that you've got 4.4 million UI events being generated - and because you're never letting the UI handle them, they're all building up with no way of them getting cleared. That would make rather more sense (even though it's still not that many objects) - but I'm unsure why you'd see this in real life - obviously the example you've given isn't a particularly realistic one, and you must have come up with it having run out of memory in a more normal program...
I believe when you do the String new Label = String.valueOf(ii);you're creating a new string. When you assign it to the label with setLabel(), there's a reference saved that's overwritten the next time around. Thus, a memory leak.
The garbage collector in Java isn't instant. When there are no more references to an object it becomes available to be garbage collected.
You're creating (and discarding) 9999 String objects. You're running out of memory before they can be collected.

Categories

Resources