51

What classes of the Java Standard API can cause memory leaks when used in an (not obviously) incorrect way? And how can these memory leaks be avoided/fixed?

Example: ObjectInputStream and ObjectOutputStream keep references to all objects they have seen in order to send subsequent occurences of the same object as references rather than copies (and thereby deal with circular references). This causes a memory leak when you keep such a stream open indefinitely (e.g. when using it to communicate over the network).

Fix: Call reset() periodically or after each top-level object.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720

6 Answers6

49

A big one is that getting substrings of Java strings refers to the original string.

Example: you read in a 3000 character record and get a substring of 12 characters, returning that to the caller (within the same JVM). Even though you don't directly have a reference to the original string, that 12 character string is still using 3000 characters in memory.

For systems that receive and then parse lots of messages, this can be a real problem.

You have a couple of ways to avoid this:

String sub = new String(str.substring(6,12));

or

String sub = str.substring(6,12).intern();

The first is more clearcut. The second has other implications because you're using PermGen space. Overused you could run out unless you give your VM enough.

Remember this is only relevant if you're taking small substrings and then throwing away the original string and you're doing this a lot.

cletus
  • 616,129
  • 168
  • 910
  • 942
  • 1
    How about mentioning a simple fix such as creating a new String object explicitly? – Yuval Adam Aug 15 '09 at 10:06
  • Not to bump a very old thread but, what is the reason for this? Why would this line "str = str.substring(6,12)" waste a space of 3k characters, instead of just 6? – Murat Derya Özen Sep 02 '11 at 16:51
  • 2
    @Murat: bumping an old comment: because it internally refers to the same char array as the original string, just with a different offset and length. If you create a lot of overlapping substrings, it actually saves memory. – Michael Borgwardt Oct 27 '11 at 07:49
  • 4
    +1: I'd say this is one of the biggest "traps" to fall into in the JDK... took me way to long to determine it was the reason my webcrawler was leaking the entire HTML source of every page it saw. Seriously, Sun/Oracle... if you're going to have an "optimization" side effect this serious, at least say something about it in [the documentation](http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#substring(int)) – rickster Sep 19 '12 at 05:04
  • 1
    Oh, and it's even worse in that it hits you whenever you use other API that's based on `substring()` internally, like the stuff in `java.util.regex`. – rickster Sep 19 '12 at 05:11
  • 2
    I checked the source code of String#substring, it will create a new String and copy a range of the internal char[]. I'm using jdk7, maybe this is fixed? – cloud May 23 '14 at 03:26
8

Everything you register as the recipient of an Event, e.g. in GUI frameworks, cannot be garbage collected as long as it is registered and the event source is alive.

This may introduce memory leaks, if a developer is not aware of that strong reference from the event source to the event subscriber.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
Black
  • 5,022
  • 2
  • 22
  • 37
7

Any non-static inner classes you make hold on to outer classes. So that innocent-looking inner class can hold onto a huge object graph. Put the instance in a static or application-wide collection somewhere and you're using a lot of memory you're not supposed to be using.

krosenvold
  • 75,535
  • 32
  • 152
  • 208
5

Each instantiation of a Thread allocates memory for a stack (default 512k, tuneable via -Xss). It's not a leak as such, but a naive attempt to heavily multi-thread an application will result in a sizable non-obvious consumption of memory.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • 3
    Actually, it can turn into an outright leak if you create Thread objects and never call start() - the stack memory is then never reclaimed, IIRC. – Michael Borgwardt Aug 15 '09 at 21:44
  • Interesting. Didn't know that. – Brian Agnew Aug 15 '09 at 22:45
  • 2
    @Michael Borgwardt: I don't think that's the case; do you have a source? \[edit\]: it looks like it may have been a bug in older versions of the JVM, but should be fixed in Java 5. – Miles Oct 27 '11 at 04:04
4

Any class with dispose() method?

For example java.awt.Window#dispose:

public void dispose()

Releases all of the native screen resources used by this Window, its subcomponents, and all of its owned children. That is, the resources for these Components will be destroyed, any memory they consume will be returned to the OS, and they will be marked as undisplayable.

Community
  • 1
  • 1
dfa
  • 114,442
  • 31
  • 189
  • 228
3

Usage of strong references when weak references would have been sufficient. Application and APIs that perform their own state and resource management are the usual culprits here.

Then, there is the usage of the Observer pattern, which could lead to memory leaks - when the Observer delists itself from the Subject, memory cannot be reclaimed unless the Subject also releases the reference to the Observer/Listener. This has already been pointed out earlier, but not many people realise that even loggers are observers.

Additionally, there is the likelihood of classes, whose objects when instantiated are automatically placed into a static member. Some of these classes do not even have a release() or a dispose() method so the references continue to be held by the static member. This variety of memory leaks eventually results in a OutOfMemory error with a PermGen space issue reported as the root cause, making it more difficult to diagnose.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Vineet Reynolds
  • 76,006
  • 17
  • 150
  • 174