substring method in String class causes memory leak

20,727

Solution 1

In past versions of the JDK, the implementation of the substring method would build a new String object keeping a reference to the whole char array, to avoid copying it. You could thus inadvertently keep a reference to a very big character array with just a one character string. Here's an example of a bug this could induce.

This method has now been changed and this "leak" doesn't exist anymore.

If you want to use an old JDK (that is older than OpenJDK 7, Update 6) and you want to have minimal strings after substring, use the constructor taking another string :

String s2 = new String(s1.substring(0,1));

As for your second question, regarding " other things which can causes of memory leak in java", it's impossible to answer in a constructive way. There aren't in java standard libs many instances of cases where you could so easily keep hidden references to objects. In the general case, pay attention to all the references you build, the most frequent problems probably arising in uncleaned collections or external resources (files, database transactions, native widgets, etc.).

Solution 2

The substring() method doesn't allocate a new character array for a String, but rather simply produces a String with a window onto the existing char array. This is an impementation of a flyweight pattern and was regarded as an optimisation.

So if I have a huge String (char array) and then create a substring, even if I garbage collect the original string, the original char array remains (despite the fact that you think you have a substring of, say, 2 chars). This problem is often encountered when (say) parsing a huge stream of input data (perhaps an XML file) and extracting a small amount of text via substring()

Using the seemingly redundant String(String str) constructor (a String constructor taking a String!) resolves this since it allocates a new (potentially smaller) char array, allowing the original to be garbage collected.

Note this behaviour has changed as of Java 7u6.

Solution 3

String substring can result in retaining more memory than you might expect. As such it's not a memory leak as this memory can be recovered normally.

The simplest solution is to use a recent version of Java 7, which doesn't do this. As this is the only freely supported version from Oracle, you should consider doing this anyway.

As such it was "fixed" in Java 7 update 5. IMHO it is not so much a fix as a simplification of the implementation. Taking a copy of every substring takes much more work and is likely to consume more memory, but it does mean there is one less thing to worry about.

What are all other things which can causes of memory leak in java?

Any object can be cleaned up as such it's not possible to create a memory leak in the C/C++ sense of the term. What you can do is hold onto objects incorrectly. A common example of this is forgetting to close resources like JDBC resource. This can cause you to retain memory in ways you don't expect.

Solution 4

In the String object, when you call substring, the value property is shared between the two strings.

So, if you get a substring from a big string and keep it for a long time, the big string won't be garbage collected. It could result in a memory leak, actually.

Share:
20,727
AmitG
Author by

AmitG

Updated on April 12, 2020

Comments

  • AmitG
    AmitG about 4 years

    It is said that substring method in String class causes memory leak. Is it true? How? What is an alternative for it?
    Especially looking for answer,
    What are all other things which can causes of memory leak in java? This will help me to take care while coding.

  • Admin
    Admin about 11 years
    Could you be more specific with past versions in which problem exists?
  • hansvb
    hansvb about 11 years
    "Problem" is a bit harsh. The implementation has changed with 7u6, so anything before that would be "affected".
  • AmitG
    AmitG about 11 years
    which version of java?
  • Denys Séguret
    Denys Séguret about 11 years
    It's gone with OpenJDK 7, Update 6.
  • Brett
    Brett about 11 years
    Note the specification has not changed. It is technically implementation dependent (although there's not much variation in implementations).
  • hansvb
    hansvb about 11 years
    One could argue that the old implementation had its advantages, too, because substring() was O(1) (not anymore), and consumed much less memory if you still needed the original String (for long Strings).
  • Denys Séguret
    Denys Séguret about 11 years
    @Thilo of course there were good reasons for the old implementations. This was after all an old trick frequently used in C. But in the age of garbage collecting, this probably caused too many bugs.
  • hansvb
    hansvb about 11 years
    Note that this is no longer the case with recent Oracle JVM.
  • Alban Dericbourg
    Alban Dericbourg about 11 years
    You're right: I should have mentioned it. Thanks for the precision!