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

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.

Related

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.

Which code is more CPU/memory efficient when used with a Garbage Collected language?

I have these two dummy pieces of code (let's consider they are written in either Java or C#, all variables are local):
Code 1:
int a;
int b = 0;
for (int i = 1; i < 10 ; i++)
{
a = 10;
b += i;
// a lot of more code that doesn't involve assigning new values to "a"
}
Code 2:
int b = 0;
for (int i = 1; i < 10 ; i++)
{
int a = 10;
b += i;
// a lot of more code that doesn't involve assigning new values to "a"
}
At first glance I would say both codes consume the same amount of memory, but Code 1 is more CPU efficient because it creates and allocates variable a just once.
Then I read that Garbage Collectors are extremely efficient to the point that Code 2 would be the more Memory (and CPU?) efficient: keeping variable a inside the loop makes it belongs to Gen0, so it would be garbage collected before variable b.
So, when used with a Garbage Collected language, Code 2 is the more efficient. Am I right?
A few points:
ints (and other primitives) are never allocated on heap. They live directly on the thread stack, "allocation" and "deallocation" are simple moves of a pointer, and happen once (when the function is entered, and immediately after return), regardless of scope.
primitives, that are accessed often, are usually stored in a register for speed, again, regardless of scope.
in your case a (and possibly, b as well, together with the whole loop) will be "optimized away", the optimizer is smart enough to detect a situation when a variable value changes, but is never read, and skip redundant operations. Or, if there is code that actually looks at a, but does not modify it, it will likely be replaced by the optimizer by a constant value of "10", that'll just appear inline everywhere where a is referenced.
New objects (if you did something like String a = new String("foo") for example instead of int) are always allocated in young generation, and only get transferred into old gen after they survive a few minor collections. This means that, for most of the cases, when an object is allocated inside a function, and never referenced from outside, it will never make it to the old gen regardless of its exact scope, unless your heap structure desperately needs tuning.
As pointed out in the comment, sometimes the VM might decide to allocate a large object directly in the old gen (this is true for java too, not just .net), so the point above only apply in most cases, but not always. However, in relation to this question, this does not make any difference, because if the decision is made to allocate an object in old gen, it is made without regard of the scope of its initial reference anyway.
From performance and memory standpoint your two snippets are identical. From the readability perspective though, it is always a good idea to declare all variables in the narrowest possible scope.
Before the code in snippet 2 is actually executed it's going to end up being transformed to look like the code in snippet 1 behind the scenes (whether it be a compiler or runtime). As a result, the performance of the two snippets is going to be identical, as they'll compile into functionally the same code at some point.
Note that for very short lived variables it's actually quite possible for them to not have memory allocated for them at all. They may well be stored entirely in a register, involving 0 memory allocation.

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).

How to garbage collect arrays of objects?

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.

Optimizing the creation of objects inside loops

Which of the following would be more optimal on a Java 6 HotSpot VM?
final Map<Foo,Bar> map = new HashMap<Foo,Bar>(someNotSoLargeNumber);
for (int i = 0; i < someLargeNumber; i++)
{
doSomethingWithMap(map);
map.clear();
}
or
final int someNotSoLargeNumber = ...;
for (int i = 0; i < someLargeNumber; i++)
{
final Map<Foo,Bar> map = new HashMap<Foo,Bar>(someNotSoLargeNumber);
doSomethingWithMap(map);
}
I think they're both as clear to the intent, so I don't think style/added complexity is an issue here.
Intuitively it looks like the first one would be better as there's only one 'new'. However, given that no reference to the map is held onto, would HotSpot be able to determine that a map of the same size (Entry[someNotSoLargeNumber] internally) is being created for each loop and then use the same block of memory (i.e. not do a lot of memory allocation, just zeroing that might be quicker than calling clear() for each loop)?
An acceptable answer would be a link to a document describing the different types of optimisations the HotSpot VM can actually do, and how to write code to assist HotSpot (rather than naive attmepts at optimising the code by hand).
Don't spend your time on such micro optimizations unless your profiler says you should do it. In particular, Sun claims that modern garbage collectors do very well with short-living objects and new() becomes cheaper and cheaper
Garbage collection and performance on DeveloperWorks
That's a pretty tight loop over a "fairly large number", so generally I would say move the instantiation outside of the loop. But, overall, my guess is you aren't going to notice much of a difference as I am willing to bet that your doSomethingWithMap will take up the majority of time to allow the GC to catch up.

Categories

Resources