Can String assignment cause memory leak? - java

In my J2ME code, I have a loop which look like this,
Enumeration jsonEnumerator = someJSONObject.keys();
while(jsonEnumerator.hasMoreElements()){
String key = (String) jsonEnumerator.nextElement();
String value = someJSONObject.getJSONObject(key);
someOtherJson.put(value,key);
}
Considering that String assignments in the above Code
String key = (String) jsonEnumerator.nextElement();
Is that the right approach to use a pool of Strings instead of instantiating new Objects or what are the other approaches to assign the strings which will avoid memory leaks?

The String assignments won't cause a memory leak.
Whether there the strings leak elsewhere in that code depends on a couple of things that can't be discerned from this code:
How the JSON implementation is creating the key and value strings. (If it is using String.substring() on a much larger String, you may leak storage via a shared string backing array.)
Whether the someOtherJson is being leaked.
The normal approach (in Java SE) is to not worry about it ... until you've got evidence from memory profiling that there is a leak. In Java ME implementations, memory is typically more constrained, and GC implementations can be relatively slow. So it can be necessary to reduce the number and size of objects (including strings). But that's not a memory leak issue ... and I'd still advise profiling first instead of leaping into a memory efficiency campaign that could be a waste of effort.
Is that the right approach to use a pool of Strings instead of instantiating new Objects or what are the other approaches to assign the strings which will avoid memory leaks?
As I said there is no leak in the above code.
String pools don't eliminate leaks, and they don't necessarily reduce the rate of garbage object creation. They can reduce the number of live String objects at any given time, but this comes at a cost.
If you want to try this approach, it is simplest to use String.intern() to manage your String pool. But it won't necessarily help. And can actually make things worse. (If there isn't enough potential for sharing, the space overheads of the interned string pool can exceed the saving. In addition, the interned string pool creates more work for the GC - more tracing, and more effectively weak references to deal with.)

No, String assignment, by itself does not create anything. The only thing resembling a "leak" in Java is when you put a whole bunch of references into some array or other structure and then forget about it -- leave the structure "live" (accessible) but don't use it.

If you're talking about interning strings, then it doesn't happen here. It only happens automatically for constant strings which are found in your source code.
Any other strings will be garbage collected, just like any other object.

My suggestion is:
Enumeration jsonEnumerator = someJSONObject.keys();
while(jsonEnumerator.hasMoreElements()) {
String key = (String) jsonEnumerator.nextElement();
someOtherJson.put(someJSONObject.getJSONObject(key), key);
}
String instantiation will cause to memory leak in J2ME because J2ME uses a poor Garbage Collection method to reduce the resource usage.
When you are trying to develop a J2ME application, be careful about memory and CPU usages.

Related

If Java has garbage collection, then why does OutOfMemoryError occur? [duplicate]

This question already has answers here:
Is the garbage collector guaranteed to run before Out of Memory Error?
(5 answers)
Closed 9 years ago.
This is a theoretical question. I am just curios that if Java has a mechanism for garbage collection to free the memory, then why does still OutOfMemoryError occur?
I searched SO for this but could get these links
Is the garbage collector guaranteed to run before Out of Memory Error?
Garbage collection before OutOfMemoryError
These do not answer my question specifically. If Java allows memory so well by using garbage collection, then why does OutOfMemoryError occur?
An OutOfMemoryError can occur if none of the objects in memory is eligible for garbage collection. For example:
List<MyClass> hellos = new ArrayList<>();
for (;;) {
hellos.add(new MyClass());
}
This creates a list and keeps adding MyClass objects to it until memory runs out. None of the objects is eligible for garbage collection because there are references to all of them.
It is also possible to sequester memory in ways you don't expect. Consider the following string example.
char[] chars = new char[10_000_000]; // May need to adjust.
String string = new String(chars);
chars = null;
String substring = string.substring(5_000_000);
string = null;
The chars array may be collected. The array inside string may not be collected, because substring contains a reference to the internal array followed by an offset and range into it. So, 107 characters remain allocated, even though only 5 * 106 are used and accessible.
Java 1.7.0_06
It seems that String.substring no longer has this behavior. In an article in the Java Performance Tuning Guide web site, Mikhail Vorontsov reports that in Java 1.7.0_06 and higher, String.substring always creates a new String independent of the old one. The String class no longer has offset and range instance variables. Creating a large string, taking substrings, and throwing away the original will not leave the old string's char[] sequestered.
// Java 1.7.0_06 and up
char[] chars = new char[10_000_000]; // May need to adjust.
String string = new String(chars);
chars = null;
String substring = string.substring(5_000_000);
// Copies a portion of string's array to a new array.
string = null;
// string's array is no longer reachable, and may be garbage collected.
Because not all memory is garbage.
Garbage collector works on memory that is not going to be used.
However, if you allocate memory, and that memory is in scope, that means, garbage collector can't really clean that memory.
When the memory allocated is too high above the allowed for the VM, you get that exception.
An object that's still has a reference to it from running code can't be collected. So if there's a way to even theoretically access an object, it's stuck in memory.
Just so it's said, Java doesn't eliminate the need to care about memory; it just automates a whole lot of the memory management stuff. You still have to do your part to ensure that you aren't squirreling away objects after their useful life is over...cause as long as they can be reached (however indirectly), they are taking up memory that can't be reclaimed.
It is better to nullify your objects once your work has been completed with them, so you make sure the objects to be available to the garbage collector in order to avoid the problems regarding out of memory or memory leak.
If you run out of memory and there is no variable or object eligible for removing, the except will be raised.
So best way to use GC(Garbage collection) is:
Explicitly assign the variable to null value if it is no used any more.

What will use more memory

I am working on improving the performance of my app. I am confused about which of the following will use more memory: Here sb is StringBuffer
String strWithLink = sb.toString();
clickHereTextview.setText(
Html.fromHtml(strWithLink.substring(0,strWithLink.indexOf("+"))));
OR
clickHereTextview.setText(
Html.fromHtml(sb.toString().substring(0,sb.toString().indexOf("+"))));
In terms of memory an expression such as
sb.toString().indexOf("+")
has little to no impact as the string will be garbage collected right after evaluation. (To avoid even the temporary memory usage, I would recommend doing
sb.indexOf("+")
instead though.)
However, there's a potential leak involved when you use String.substring. Last time I checked the the substring basically returns a view of the original string, so the original string is still resident in memory.
The workaround is to do
String strWithLink = sb.toString();
... new String(strWithLink.substring(0,strWithLink.indexOf("+"))) ...
^^^^^^^^^^
to detach the wanted string, from the original (potentially large) string. Same applies for String.split as discussed over here:
Java String.split memory leak?
The second will use more memory, because each call to StringBuilder#toString() creates a new String instance.
http://www.docjar.com/html/api/java/lang/StringBuilder.java.html
Analysis
If we look at StringBuilder's OpenJDK sources:
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
We see, that it instantiates a whole new String object. It places in the string pool as many new instances as many times you call sb.toString().
Outcome
Use String strWithLink = sb.toString();, reusing it will retrieve the same instance of String from the pool, rather the new one.
Check other people's answers, the second one does take a little bit more memory, but this sounds like you are over optimizing. Keeping your code clear and readable should be the priority. I'd suggest you don't worry so much about such tiny optimizations if readability will suffer.
The less work you do, the more efficient it usually is. In this case, you don't need to call toString at all
clickHereTextview.setText(Html.fromHtml(sb.substring(0, sb.indexOf("+"))));
Creating new objects always take up more memory. However, in your case difference seems insignificant.
Also, in your case, you are creating a local variable which takes heap space.
Whenever there are references in more than one location in your method it good to use
String strWithLink = sb.toString();, as you can use the same strWithLink everywhere . Otherwise, if there is only one reference, its always better to just use sb.toString(); directly.

If the object is referenced as then it is automatically frees the memory in j2me or not frees the memory in j2me?

Im a j2me developer. Now im developing a mobile application using j2me.
I had a doubt,
In java, If a create an object , then after some time we does not want it means,we make it null ,then it is automatically frees the memory and goes to garbage collection.
String str1=new String("Thamilan"); //Allocating a memory for str1
.......
......
str1=null; //Frees the memory of str1
The above code str1=null frees memory, My doubt is like that if we refer any object to null then it is goes to garbage collection (memory frees) in j2me is correct or not.
Please help me. The answer is very helpful to me. Because i had a problem of memory constraints in my mobile application.
Thanks & Regards
Yes, if all references to an object go away, it becomes eligible for garbage collection and the memory for it will eventually be freed. This will in general not happen immediately, but sometime later in a background thread or when the program threatens to run out of memory. This is true for J2ME as well.
What you should take care of in J2ME (even more so than in general) is to preserve memory at the allocating end, i.e. not create huge amounts of objects in the first place if it can be avoided.
PS:
String str1 = new String("Thamilan")
is better written as (and uses more memory than)
String str1 = "Thamilan";
String str1=new String("Thamilan"); //Allocating a memory for str1
.......
......
str1=null; //Frees the memory of str1
If all references go away, then memory will eventually be freed. But beware that writing this kind of code in stack (i.e. local variables, inside methods) offers no advantage at all; the compiler can infer if the variable can't be referenced after some point, so explicitly setting it to null has no effect whatsoever; the assignment will probably be optimized away immediately.
For heap (i.e. instance variables, inside classes) this kind of nulling may be useful, though. The compiler or the JVM has no way to know if someone is going to reference that variable in the future, possibly via reflection, so it must keep the object around unless its reference is null'd.
Better calling System.gc(); to call the garbage collection.

If Java Strings are immutable and StringBuilder is mutable why they wasting same amount of memory in my code?

I ran those code and I got some questions, this kinda got weird.
Using String:
while(true)
{
String s = String.valueOf(System.currentTimeMillis());
System.out.println(s);
Thread.sleep(10);
}
Using StringBuilder:
StringBuilder s = null;
while(true)
{
s = new StringBuilder();
s.append(System.currentTimeInMillis());
System.out.println(s);
Thread.sleep(10);
}
In both cases they get stuck in 12540 K waste of memory. Running this test on Windows XP SP2.
Why are they wasting the same amount of memory?
Why did immutable String stop wasting memory?
Off-topic: How can I convert StringBuilder to byte array encoded in a specific charset?
It is hard to figure out what you are actually asking here, but the application is behaving exactly as I would expect.
Strings are immutable and the garbage collector doesn't take them out. isn't it
Both mutable and immutable objects may be garbage collected in Java.
The actual criterion that determines whether an object is actually garbage collected is it reachability. In simple terms, when the garbage collector figures out that the application can no longer use an object, the object will be deleted.
In both of your applications, objects of roughly the same size are being created once every 10 milliseconds. In each iteration, a new object is being created and its reference is being assigned to s, replacing the previous reference. This makes the previous object unreachable, and eligible for garbage collection. At some point, the Java VM decides to run the garbage collector. This gets rid of all of the unreachable object ... and the application continues.
I read that common Strings are not collected ever by the garbage collector, is that false?
This is false on two counts:
Strings created by new String(...), String.substring(...)1 and so on are no different from any other Java object.
Strings that are interned (by calling String.intern()) are stored in the string pool which is held in the PermGen heap2. However, even the PermGen heap is garbage collected, albeit on longer timescales that the heap in which objects are normally created.
(Once upon a time, the PermGen heap was not garbage collected, but that was changed a long time ago.)
As #MichaelBorgwardt correctly identified, you were confusing string objects (in general) with string objects that correspond to string literals. The latter are interned automatically, and end up in the string pool. However, they may still be subject to garbage collection. This can happen if the parent class is unloaded and nothing else references the literal.
1 - In Java 6 and earlier, there is a difference between strings created using new String and using String.substring. In the latter case, the original string and the substring would share the backing array that holds the string's characters. In Java 7, this changed. String.substring now creates a new backing array.
2 - From Java 7 onwards, the string pool is just a (hidden) data structure in the normal heap. From Java 8 onwards, the PermGen heap no longer exists.
You are confusing two very different things:
Strings are immutable, but this has nothing to do with whether or not they are garbage collected. However, it means that if you need to make a lot of changes to a String (such as building a big string by appending one character at a time), then you end up making lots of copies and a lot of work for the garbage collector.
String literals (i.e. Strings that are written directly in the source code) are part of a pool of interned Strings and generally not garbage collected. However, this is done in order to allow multiple instances of the same String in the source code to be replaced by references to the same object, which can save a lot of space. And this is only possible because Strings are immutable, so two parts of the program holding a reference to the same String cannot interfere with each other.
You seem to assume that a mutable class would waste more memory than a non-mutable class. I don't understand why.
Your code is wrong, if it's intended to allocate more memory in each loop. It just assigns the s reference to a new object, hence the previous one is lost and will be garbage collected eventually.
To look at the OS memory for the JVM is a very rough/imprecise estimation of the Java allocated memory.
StringBuilder and String (and StringBuffer and char[] ) are all efficient, they allocate approximately 2 bytes per char (Java uses some UTF-16 variation) plus a small (negligible for big strings) overhead.
Because you are building and throwing. In fact, you are not really building any string using StringBuilder. Notice, you are instantiating a new StringBuilder object in every go.
As already explained, since you are not mutating the string but rather just pointing s to a new value; the old value has to be garbage collected. Here is a snippet using stringBuffer to try to actually mutate the value s is pointing to.
StringBuffer s = new StringBuffer();
while(true)
{
s.replace(0,13,Long.toString(System.currentTimeMillis()));
System.out.println(s);
Thread.sleep(10);
}
It should be noted that this doesn't solve the problem because of two things. First of all we have to make a new String everytime using Long.toString(), and secondly since s.toString() will be called; this will make a new String sharing the value of stringBuffer (atleast this was the case last time I checked). When we do s.replace it will allocate a new array to hold this new string in order to preserve the unmutability of the String.
Actually, In this trivial case, the best you can do (as far as I know) is:
while(true)
{
System.out.println(Long.toString(System.currentTimeMillis()));
Thread.sleep(10);
}
Wanted to post this as a reply to Stephen C, but for some reason I can't; so here is a point of clarification...
String.subString(...) does NOT create a new String. It references a point within an existing String, and returning substring values is one sure way to introduce memory leaks into your app (especially if building a list of Strings based on substring values of another list of strings).
Best practice in this case is:
return new String(s.subString(...));

Use PermGen space or roll-my-own intern method?

I am writing a Codec to process messages sent over TCP using a bespoke wire protocol. During the decode process I create a number of Strings, BigDecimals and dates. The client-server access patterns mean that it is common for the client to issue a request and then decode thousands of response messages, which results in a large number of duplicate Strings, BigDecimals, etc.
Therefore I have created an InternPool<T> class allowing me to intern each class of object. Internally, the pool uses a WeakHashMap<T, WeakReference<T>>. For example:
InternPool<BigDecimal> pool = new InternPool<BigDecimal>();
...
// Read BigDecimal from in buffer and then intern.
BigDecimal quantity = pool.intern(readBigDecimal(in));
My question: I am using InternPool for BigDecimal but should I consider also using it for String instead of String's intern() method, which I believe uses PermGen space? What is the advantage of using PermGen space?
If you already have such a InternPool class, it think it is better to use that than to choose a different interning method for Strings. Especially since String.intern() seems to give a much stronger guarantee than you actually need. Your goal is to reduce memory usage, so perfect interning for the lifetime of the JVM is not actually necessary.
Also, I'd use the Google Collections MapMaker to create a InternPool to avoid re-creating the wheel:
Map<BigDecimal,BigDecimal> bigDecimalPool = new MapMaker()
.weakKeys()
.weakValues()
.expiration(1, TimeUnits.MINUTES)
.makeComputingMap(
new Function<BigDecimal, BigDecimal>() {
public BigDecimal apply(BigDecimal value) {
return value;
}
});
This would give you (correctly implemented) weak keys and values, thread safety, automatic purging of old entries and a very simple interface (a simple, well-known Map). To be sure you could also wrap it using Collections.immutableMap() to avoid bad code messing with it.
It is likely that the JVM's String.intern() pool will be faster. AFAIK, it is implemented in native code, so it should be faster and use less space than a pool implemented using WeakHashMap and WeakReference. You would need to do some careful benchmarking to confirm this.
However, unless you have huge numbers of long-lived duplicate objects, I doubt that interning (either in permGen or with your own pools) will make much difference. And if the ratio of unique to duplicate objects is too low, then interning will just increase the number of live objects (making the GC take longer) and reduce performance due the overheads of interning, and so on. So I would also advocate benchmarking the "intern" versus "no intern" approaches.

Categories