6

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.

Henrik P. Hessel
  • 36,243
  • 17
  • 80
  • 100
  • 4
    I guess it depends on how the J2ME garbage collector works, but reassigning `input` to anything (`null`, `""`, or `"I like pizza"`) should let the GC reclaim the huge input string. – Michael Myers Jul 24 '09 at 18:31
  • See also http://stackoverflow.com/questions/473685/does-it-help-gc-to-null-local-variables-in-java – Kevin Panko Jul 24 '09 at 18:54
  • 1
    Sorry, I don't know the answer. I just know a wrong answer when I see it. – Michael Myers Jul 25 '09 at 14:34

6 Answers6

12

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
  • 62,186
  • 18
  • 105
  • 157
  • 3
    so 'null' might consume a bit less memory than "" but both ought to be better than some huge string – mpen Jul 24 '09 at 19:02
  • 4
    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 Jul 27 '09 at 06:46
5

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.

Esteban Küber
  • 36,388
  • 15
  • 79
  • 97
  • 8
    But either way, the old string has no references, so it should be eligible for collection. – Michael Myers Jul 24 '09 at 18:32
  • 4
    Either one changes what input refers to so they will have the same effect from the garbage collectors perspective. – Graphics Noob Jul 24 '09 at 18:36
  • 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. – Esteban Küber Jul 24 '09 at 18:45
  • 7
    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 Jul 24 '09 at 18:47
  • 1
    @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 Jul 24 '09 at 19:38
  • @Kevin,Pavel: I were mistaken by some bad tip I were taught at university, that I'm happy to have corrected. – Esteban Küber Jul 25 '09 at 16:40
5

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

Community
  • 1
  • 1
nairdaen
  • 1,037
  • 2
  • 11
  • 19
  • This is actually a much better solution. – Bill K Jul 24 '09 at 18:37
  • 2
    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 Jul 24 '09 at 19:01
  • 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 Jul 24 '09 at 19:44
3

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
  • 8,356
  • 19
  • 50
  • 61
  • 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 Jul 25 '09 at 21:06
2

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, butif (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.
  • 7,739
  • 7
  • 39
  • 54
  • 1
    `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 Jul 24 '09 at 19:22
  • 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 Jul 24 '09 at 19:23
  • @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 Jul 24 '09 at 19:26
  • 1
    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 Jul 24 '09 at 19:33
  • 1
    It doesn't keep reference counts *per se*, but any strong reference will prevent the GC from reclaiming an object. – Michael Myers Jul 24 '09 at 19:34
  • 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. Aug 13 '09 at 19:16
1

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.

mnuzzo
  • 3,529
  • 4
  • 26
  • 29