views:

834

answers:

7

I'm running a J2ME Application and run into some serious memory problems.
So I built in another step to clear the huge input string and process its data and clear it. But it didn't solve the problem until I set input = null and not input = "".

Shouldn't it be the same in terms of memory management? Can somebody explain me the difference please?

Thanks,
rAyt

for(int x = 0; x <= ChunksPartCount; x++)
{
 _model.setLoading_bar_progress((x * ChunkSize));
 input += web_service.FullCompanyListChunksGet(x, ChunkSize);

 if((x * ChunkSize) > 5000)
 {
  ReadXML(input);
  input = null;
 }
}

Edit:
I still want to flag an answer as the solution. I think mmyers remarks are going in the right direction.

+5  A: 

input = null deletes (let's the Garbage collector delete) the object in memory, while input = "" instantiates an String object containing the empty string "". By setting input to null, you are making input an empty object, so it won't take any memory, while setting input = "", you are setting it to a new object, that will definitely take some memory (obviously it should be minimal).

You could look into this article from IBM talking about Java GC and performance, that discourages my previous recommendation. It says:

Explicit nulling is simply the practice of setting reference objects to null when you are finished with them. The idea behind nulling is that it assists the garbage collector by making objects unreachable earlier. Or at least that's the theory.

There is one case where the use of explicit nulling is not only helpful, but virtually required, and that is where a reference to an object is scoped more broadly than it is used or considered valid by the program's specification. This includes cases such as using a static or instance field to store a reference to a temporary buffer, rather than a local variable, or using an array to store references that may remain reachable by the runtime but not by the implied semantics of the program.

And furthermore,

In the September 1997 "Java Developer Connection Tech Tips" column (see Resources), Sun warned of this risk and explained how explicit nulling was needed in cases like the pop() example above. Unfortunately, programmers often take this advice too far, using explicit nulling in the hope of helping the garbage collector. But in most cases, it doesn't help the garbage collector at all, and in some cases, it can actually hurt your program's performance.

voyager
But either way, the old string has no references, so it should be eligible for collection.
Michael Myers
Either one changes what input refers to so they will have the same effect from the garbage collectors perspective.
Graphics Noob
You are right, the original content of input should be deleted as soon as both ReadXML and input don't reference to it anymore. But by seting input to null, you *are* telling the GC delete this as soon as possible.
voyager
There's nothing special about setting a reference variable to null compared to any other value. It definitely isn't some magic signal to GC to "delete as soon as possible".
Pavel Minaev
@voyager Where does it say that setting a variable to null tells the GC to "delete this as soon as possible?" I do not think that is true.
Kevin Panko
@Kevin,Pavel: I were mistaken by some bad tip I were taught at university, that I'm happy to have corrected.
voyager
+3  A: 

Using a StringBuffer could be a better approach

Some of this has already been answered here in SO:

String builder and stringbuffer in java

why to use StringBuffer in java instead of the string concantion operator

nairdaen
thanks for input, why?
Henrik P. Hessel
This is actually a much better solution.
Bill K
Every time you write `input += blah()` a new String object gets created, all content from the old one gets copied into that with the output from `blah()` appended, and the old `input` is marked for GC. This is very slow and inefficient. `StringBuffer` solves it.
Thomas
Efficiency isn't his issue here. He has a question about the underlying implementation of null versus an empty string. So, you didn't answer his question. Had he been asking about performance, then it would be good to tell him to profile the code for bottlenecks. Had he found a problem caused by copious string concatenation, then advising the use StringBuffer would be a good answer to that question. But why tell him how to optimize when you don't know that he has a performance problem, and wasn't even asking about it?
Don Branson
+10  A: 

Every variable is actually a pointer to "Data" in memory.

input = "" assigns input to a string object. It has a length (0) and an empty array, as well as a few other pieces of data associated with it.

input.length() will return 0 at this point.

input = null makes input point to "Invalid". Null is kind of a special case that means this pointer points to NOTHING, it's unassigned.

input.length() will now throw an exception because you are calling .length on nothing.

Bill K
so 'null' might consume a bit less memory than "" but both ought to be better than some huge string
Mark
Yes, but I get a really funky feeling whenever anyone "Empties" a variable. The one in the example should be a method variable and should therefore go away the second the method exits. Setting it to null or "" probably just hurts since it's more for the runtime to optimize. In other words, if input=null does anything above, it means input isn't scoped well enough--fix that first!
Bill K
+1  A: 

In Java Strings are objects and object variable names are always pointers. If you have a String called input and type input = null, that points input to a null space in memory. If you have input = "", it creates a String which contains no text, an empty string.

indyK1ng
+2  A: 

I would like to add a bit to voyager's answer:

Regarding Strings

The statement input = ""; from a garbage collection standpoint is the same as writing input = "abcde...";, in that neither statement nullifies the object instance input, but both just change the contents of the input String variable. Also, for precision and clarification, input = something" changes the contents of input, while String input = ""; instantiates input.

If input == "", then 'if (input.isEmpty()) would be true, but if (input == null)` would be false.

Regarding Garbage Collection

The statement input = null; decrements the reference count on this specific object instance, which, if it is the last reference to input, then input will be flagged for garbage collection which will happen non-deterministically AKA when the garbage collector gets to it. A case where input = null; would not actually flag input for garbage collection would be: if input was also passed into a collection; until input was removed from the collection it would keep the reference count from decrementing and therefore from being garbage collected.

Hope this helps and to anyone else out there please feel free to correct any errors even if they are subtle.

-bn

bn
`input = ""` does *not* "change the contents of the `input String` variable"; it merely reassigns it, decrementing the reference count on the original string. From the point of view of the original huge string, *any* reassignment of `input` decrements the reference count, and it makes no difference to it whether the reassigment is to `""`, `null`, or `"Jon Skeet"`.
Michael Myers
I see, you're saying that `input = "";` doesn't means that the old value of `input` has to be marked in the "mark" phase before it can be collected in the "sweep" phase, while `input = null;` causes it to be marked, so you only need to wait for a "mark" phase?
Imagist
@mmyers I was under the impression that Java's GC didn't keep reference counts because with generational GC it would take up more memory than it is worth.
Imagist
It's important to remember that variables are references to objects, not objects themselves. Java String objects are immutable -- unchangable. You can only change what a variable references, not the String object itself.@imageist Yes, Java does not keep reference counts, it actually figures out if an object is referenced by any variable by following the reference graph at runtime.
Kevin Panko
It doesn't keep reference counts *per se*, but any strong reference will prevent the GC from reclaiming an object.
Michael Myers
mmyers, Could you please elaborate on your July 24 19:34 statement? Specifically I'm curious about the "per se" statement; I would like to understand the GC better (speaking of which, do you have a recommendation or preferred source to go for about the inner workings of the JVM, GC, and so on?)
bn
+3  A: 

Rather than speculating as to why the garbage collector would not collect your object, I prefer to gather evidence about the situation. Others have already posted their guesses.

If possible, create heap dump files to observe the memory in your JVM as it runs your code, then inspect them to see what objects are there.

Here is a web page that tells you how to do that: http://twit88.com/blog/2008/12/19/java-troubleshooting-memory-problem/

Good luck!


Another idea: Write a short program that does nothing more than create large String objects and then turn on verbose garbage collection mode, to see what happens there. If you can reproduce the behavior in a small program, then you can study it more easily. I think you may find that the JVM on a PC may behave differently than the JVM in a J2ME device like a cell phone.

Kevin Panko
The reason that I cannot answer this question is, I would not expect Java to behave this way. It should make no difference between s = null or s = "". rAyt stated that it did make a difference, so there must be a gap in my understanding. I learn best by reading information from authoritative sources (Sun and IBM are good) and direct experimentation.
Kevin Panko
A: 

I'm not entirely shure about j2me, but in general Strings are not garbage collected. They exist in StringHeap, which has some clever optimizations, like reuse, but it is excluded from garbage collection. StringBuffer should therefor be a better alternative for large strings with a short lifespan, as they are garbage collected.

Jaap
No -- In general, Strings do get garbage collected. String literals and other intern'ed Strings, can be stored in the JVM's permanent generation, and therefore not garbage collected.
Kevin Panko
StringHeap?!? You're making stuff up.
John M
@John M. Thanks for the downvote, you really know how to get people to participate.
Jaap