3428

I just had an interview, and I was asked to create a memory leak with Java.

Needless to say, I felt pretty dumb having no clue on how to even start creating one.

What would an example be?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
MatBanik
  • 24,206
  • 38
  • 107
  • 172

59 Answers59

2434

Here's a good way to create a true memory leak (objects inaccessible by running code but still stored in memory) in pure Java:

  1. The application creates a long-running thread (or use a thread pool to leak even faster).
  2. The thread loads a class via an (optionally custom) ClassLoader.
  3. The class allocates a large chunk of memory (e.g. new byte[1000000]), stores a strong reference to it in a static field, and then stores a reference to itself in a ThreadLocal. Allocating the extra memory is optional (leaking the class instance is enough), but it will make the leak work that much faster.
  4. The application clears all references to the custom class or the ClassLoader it was loaded from.
  5. Repeat.

Due to the way ThreadLocal is implemented in Oracle's JDK, this creates a memory leak:

  • Each Thread has a private field threadLocals, which actually stores the thread-local values.
  • Each key in this map is a weak reference to a ThreadLocal object, so after that ThreadLocal object is garbage-collected, its entry is removed from the map.
  • But each value is a strong reference, so when a value (directly or indirectly) points to the ThreadLocal object that is its key, that object will neither be garbage-collected nor removed from the map as long as the thread lives.

In this example, the chain of strong references looks like this:

Thread object → threadLocals map → instance of example class → example class → static ThreadLocal field → ThreadLocal object.

(The ClassLoader doesn't really play a role in creating the leak, it just makes the leak worse because of this additional reference chain: example class → ClassLoader → all the classes it has loaded. It was even worse in many JVM implementations, especially prior to Java 7, because classes and ClassLoaders were allocated straight into permgen and were never garbage-collected at all.)

A variation on this pattern is why application containers (like Tomcat) can leak memory like a sieve if you frequently redeploy applications which happen to use ThreadLocals that in some way point back to themselves. This can happen for a number of subtle reasons and is often hard to debug and/or fix.

Update: Since lots of people keep asking for it, here's some example code that shows this behavior in action.

Daniel Pryden
  • 54,536
  • 12
  • 88
  • 131
  • 201
    +1 ClassLoader leaks are some of the most commonly painful memory leaks in the JEE world, often caused by 3rd party libs that transform data (BeanUtils, XML/JSON codecs). This can happen when the lib is loaded outside your application's root classloader but holds references to your classes (eg. by caching). When you undeploy/redeploy your app the JVM is unable to garbage collect the app's classloader (and therefore all classes loaded by it), so with repeat deploys the app server eventually borks. If lucky you get a clue with ClassCastException z.x.y.Abc cannot be cast to z.x.y.Abc – earcam Jun 27 '11 at 16:55
  • 61
    +1: Classloader leaks are a nightmare. I spent weeks trying to figure them out. The sad thing is, as what @earcam has said, they are mostly caused by 3rd party libs and also most profilers can't detect these leaks. There's a good and clear explanation on this blog about Classloader leaks. http://blogs.oracle.com/fkieviet/entry/classloader_leaks_the_dreaded_java – Adrian M Jul 08 '11 at 09:08
1268

Static field holding an object reference [especially a final field]

class MemorableClass {
    static final ArrayList list = new ArrayList(100);
}

Calling String.intern() on a lengthy string

String str = readString(); // read lengthy string any source db,textbox/jsp etc..
// This will place the string in memory pool from which you can't remove
str.intern();

(Unclosed) open streams (file , network, etc.)

try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

Unclosed connections

try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

Areas that are unreachable from JVM's garbage collector, such as memory allocated through native methods.

In web applications, some objects are stored in application scope until the application is explicitly stopped or removed.

getServletContext().setAttribute("SOME_MAP", map);

Incorrect or inappropriate JVM options, such as the noclassgc option on IBM JDK that prevents unused class garbage collection

See IBM JDK settings.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Prashant Bhate
  • 10,130
  • 7
  • 42
  • 81
  • 193
    I'd disagree that context and session attributes are "leaks." They're just long-lived variables. And the static final field is more or less just a constant. Maybe large constants should be avoided, but I don't think it's fair to call it a memory leak. – Ian McLaird Jul 13 '11 at 04:08
  • 88
    *(Unclosed) open streams ( file , network etc... )*, doesn't leak for real, during finalization (which will be after the next GC cycle) close() is going to be scheduled (`close()` is usually not invoked in the finalizer thread since might be a blocking operation). It's a bad practice not to close, but it doesn't cause a leak. Unclosed java.sql.Connection is the same. – bestsss Jul 17 '11 at 18:38
  • 37
    In most sane JVMs, it appears as though the String class only has a weak reference on its `intern` hashtable contents. As such, it *is* garbage collected properly and not a leak. (but IANAJP) http://mindprod.com/jgloss/interned.html#GC – mbauman Jul 22 '11 at 01:32
  • loved this answer from Prashant Bhate. –  Apr 22 '21 at 14:03
472

A simple thing to do is to use a HashSet with an incorrect (or non-existent) hashCode() or equals(), and then keep adding "duplicates". Instead of ignoring duplicates as it should, the set will only ever grow and you won't be able to remove them.

If you want these bad keys/elements to hang around you can use a static field like

class BadKey {
   // no hashCode or equals();
   public final String key;
   public BadKey(String key) { this.key = key; }
}

Map map = System.getProperties();
map.put(new BadKey("key"), "value"); // Memory leak even if your threads die.
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Peter Lawrey
  • 498,481
  • 72
  • 700
  • 1,075
  • @delnan, not providing a hashCode()/equals() is enough. – Peter Lawrey Jun 24 '11 at 16:20
  • 73
    Actually, you can remove the elements from a HashSet even if the element class gets hashCode and equals wrong; just get an iterator for the set and use its remove method, as the iterator actually operates on the underlying entries themselves and not the elements. (Note that an unimplemented hashCode/equals is _not_ enough to trigger a leak; the defaults implement simple object identity and so you can get the elements and remove them normally.) – Donal Fellows Jun 25 '11 at 17:23
  • 2
    @Donal your last statement is incorrect. You can't get the element because you have no reference to it. The only reference to the key put in the map is the one that the map itself holds. Only if you went `BadKey myKey = new BadKey("key"); map.put(key,"value");` would you ever be able to get it out. You are correct you could use the iterator to remove it, but you cannot always do that with all data structures. For example, if you don't null out the reference in @meriton's answer, that will be lost forever. You have no access to the backing array, and iterator will stop short of it. – corsiKa Jun 26 '11 at 00:13
  • The only way to remove elements when equals/hashCode is incorrect is to use Iterator.remove() when you find a match using a different method of comparison. – Peter Lawrey Jun 26 '11 at 07:14
  • 1
    @Total: But I wasn't addressing the problem of *all* data structures; it's always possible to make stupid code that doesn't delete stuff despite being asked to. (That's when the right thing to do is to GC the source code to that class. Possibly its author too.) I was addressing a `HashSet` where what I said is true; no matter how bad the element implementation is, you can still give it the boot. (I double-checked the source code.) – Donal Fellows Jun 26 '11 at 09:56
  • 13
    @Donal what I'm trying to say, I guess, is I disagree with your definition of a memory leak. I would consider (to continue the analogy) your iterator-removal technique to be a drip-pan under a leak; the leak still exists regardless of the drip pan. – corsiKa Jun 26 '11 at 20:24
  • 101
    I agree, this is **not** a memory "leak", because you can just remove references to the hashset and wait for the GC to kick in, and presto! the memory goes back. – user541686 Jul 02 '11 at 04:30
  • @PeterLawrey: you asked me if I had "facts" in this question: http://stackoverflow.com/questions/4400311 The +130 upvotes to examples in this question and *bestssss*' answer is basically all the facts I need. Your comment was snarky and upvoted by ten Java fanboism. I'm still sad my question is at -1 (because people like you downvoted it or encouraged the downvoting with snarky comments). – SyntaxT3rr0r Jul 22 '11 at 11:43
  • 13
    @SyntaxT3rr0r, I interpreted your question as asking if there is anything in the language which naturally leads to memory leaks. The answer is NO. This questions asks if it is possible to contrive a situation to create something like a memory leak. None of these examples are memory leak in the manner that a C/C++ programmer would understand it. – Peter Lawrey Jul 22 '11 at 12:32
  • @SyntaxT3rr0r, In my example, as soon as you discard the map the "memory leak" will disappear. There are example here were memory must be consumed until the program exists. It is no possible to implement the functionality without using memory and cannot be considered a bug any more than loading the Object class is a memory leak. You should also read Darien's comment. – Peter Lawrey Jul 22 '11 at 12:37
  • @Peter Lawrey: if the examples are not memory leaks in the manner that a C/C++ programmer would understand it then maybe we can infer from context (the context being *"Java and Java not having the same memory leak C/C++ does"*) that we're talking about all the various memory leaks given by *bestssss* and the one by Daniel Pryden etc.? By know this question + answers are reaching more than +800 upvotes and it seems pretty much accepted that, after all, Java does have memory leaks. Where did I (or the OP) mention memory leak in a C/C++ way? – SyntaxT3rr0r Jul 22 '11 at 12:50
  • @Peter Lawrey: for years people have been telling that Java had no memory leaks and this mislead people into thinking that automated GC meant they'd never leak memory again. This was a blatant (and persistent) lie that caught on. Thankfully there were great articles (on *DeveloperWorks* and *Artima* for example) exposing the fallacy in that cliche: *"Java memory leaks are not the same as C/C++ ones hence Java doesn't leak memory"* and now, even better, this question contains answers showing **real** Java leaks. – SyntaxT3rr0r Jul 22 '11 at 12:54
  • 13
    @Peter Lawrey: also, what do you think about this: *"There's not anything in the C language which naturally leaks to memory leak if you don't forget to manually free the memory you allocated"*. How would that be for intellectual dishonesty? Anyway, I'm tired: you can have the last word. – SyntaxT3rr0r Jul 22 '11 at 12:56
  • @SyntaxT3rr0r, This questions talks about "memory leaks" in the context of functions which consume memory as a part of there normal operation. Your usage of "memory leaks" indicate a bug which shouldn't consume memory (a negative thing). i.e. If only a better language were used, these memory leaks wouldn't happen. Your statement that "Here are the facts ... a lot of Java programs have (subtle or not) memory leaks" is hard to support as people can't even agree what a memory leak means in Java. You appear to agree that the C/C++ standard understand of the term *never happens*. – Peter Lawrey Jul 22 '11 at 13:51
  • 8
    @SyntaxT3rr0r: All your posts seem to revolve around accusations of "fanboyism" and "blatant lies" and "intellectual dishonesty"... If you want to hate on Java I'm sure there's some forum far from here where you can make angry rants much more easily without polluting the technical conversation. – Darien Jul 22 '11 at 18:23
  • 7
    @SyntaxT3rr0r, On reflection, I think you have a good point to make, but you appeal to emotive rather than technical arguments. – Peter Lawrey Jul 22 '11 at 18:27
  • 5
    @SyntaxT3rr0r, I have written a more detailed response to your interesting question http://vanillajava.blogspot.com/2011/07/java-and-memory-leaks.html – Peter Lawrey Jul 22 '11 at 22:33
284

Below there will be a non-obvious case where Java leaks, besides the standard case of forgotten listeners, static references, bogus/modifiable keys in hashmaps, or just threads stuck without any chance to end their life-cycle.

  • File.deleteOnExit() - always leaks the string, if the string is a substring, the leak is even worse (the underlying char[] is also leaked) - in Java 7 substring also copies the char[], so the later doesn't apply; @Daniel, no needs for votes, though.

I'll concentrate on threads to show the danger of unmanaged threads mostly, don't wish to even touch swing.

  • Runtime.addShutdownHook and not remove... and then even with removeShutdownHook due to a bug in ThreadGroup class regarding unstarted threads it may not get collected, effectively leak the ThreadGroup. JGroup has the leak in GossipRouter.

  • Creating, but not starting, a Thread goes into the same category as above.

  • Creating a thread inherits the ContextClassLoader and AccessControlContext, plus the ThreadGroup and any InheritedThreadLocal, all those references are potential leaks, along with the entire classes loaded by the classloader and all static references, and ja-ja. The effect is especially visible with the entire j.u.c.Executor framework that features a super simple ThreadFactory interface, yet most developers have no clue of the lurking danger. Also a lot of libraries do start threads upon request (way too many industry popular libraries).

  • ThreadLocal caches; those are evil in many cases. I am sure everyone has seen quite a bit of simple caches based on ThreadLocal, well the bad news: if the thread keeps going more than expected the life the context ClassLoader, it is a pure nice little leak. Do not use ThreadLocal caches unless really needed.

  • Calling ThreadGroup.destroy() when the ThreadGroup has no threads itself, but it still keeps child ThreadGroups. A bad leak that will prevent the ThreadGroup to remove from its parent, but all the children become un-enumerateable.

  • Using WeakHashMap and the value (in)directly references the key. This is a hard one to find without a heap dump. That applies to all extended Weak/SoftReference that might keep a hard reference back to the guarded object.

  • Using java.net.URL with the HTTP(S) protocol and loading the resource from(!). This one is special, the KeepAliveCache creates a new thread in the system ThreadGroup which leaks the current thread's context classloader. The thread is created upon the first request when no alive thread exists, so either you may get lucky or just leak. The leak is already fixed in Java 7 and the code that creates thread properly removes the context classloader. There are few more cases (like ImageFetcher, also fixed) of creating similar threads.

  • Using InflaterInputStream passing new java.util.zip.Inflater() in the constructor (PNGImageDecoder for instance) and not calling end() of the inflater. Well, if you pass in the constructor with just new, no chance... And yes, calling close() on the stream does not close the inflater if it's manually passed as constructor parameter. This is not a true leak since it'd be released by the finalizer... when it deems it necessary. Till that moment it eats native memory so badly it can cause Linux oom_killer to kill the process with impunity. The main issue is that finalization in Java is very unreliable and G1 made it worse till 7.0.2. Moral of the story: release native resources as soon as you can; the finalizer is just too poor.

  • The same case with java.util.zip.Deflater. This one is far worse since Deflater is memory hungry in Java, i.e. always uses 15 bits (max) and 8 memory levels (9 is max) allocating several hundreds KB of native memory. Fortunately, Deflater is not widely used and to my knowledge JDK contains no misuses. Always call end() if you manually create a Deflater or Inflater. The best part of the last two: you can't find them via normal profiling tools available.

(I can add some more time wasters I have encountered upon request.)

Good luck and stay safe; leaks are evil!

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
bestsss
  • 10,864
  • 3
  • 49
  • 62
  • 26
    `Creating but not starting a Thread...` Yikes, I was badly bitten by this one some centuries ago! (Java 1.3) – leonbloy Jul 09 '11 at 01:54
  • @leonbloy, before it was even worse as the thread was added straight to the threadgroup, not starting meant very hard leak. Not it just increases the `unstarted` count but that prevents the thread group from destroying (lesser evil but still a leak) – bestsss Jul 09 '11 at 06:52
  • Thank you! **"Calling `ThreadGroup.destroy()` when the ThreadGroup has no threads itself..."** is an incredibly subtle bug; I've been chasing this for hours, led astray because enumerating the thread in my control GUI showed nothing, but the thread group and, presumably, at least one child group would not go away. – Lawrence Dol Nov 08 '17 at 02:47
  • 2
    @bestsss : I'm curious, why would you want to remove a shutdown hook, given that it runs at, well, JVM shutdown? – Lawrence Dol Nov 09 '17 at 21:09
  • 1
    @LawrenceDol you're no longer interested in knowing when the JVM shuts down? – user253751 Sep 10 '20 at 15:12
  • @user253751 : This is in the context of memory leaks. In that context failing to remove a shutdown hook after it's used is not a leak because the JVM is shutting down. Granted, though, if you only temporarily need to do something on shutdown, then not removing it and continually adding new handlers would leak. – Lawrence Dol Sep 11 '20 at 16:08
219

Most examples here are "too complex". They are edge cases. With these examples, the programmer made a mistake (like don't redefining equals/hashcode), or has been bitten by a corner case of the JVM/JAVA (load of class with static...). I think that's not the type of example an interviewer want or even the most common case.

But there are really simpler cases for memory leaks. The garbage collector only frees what is no longer referenced. We as Java developers don't care about memory. We allocate it when needed and let it be freed automatically. Fine.

But any long-lived application tend to have shared state. It can be anything, statics, singletons... Often non-trivial applications tend to make complex objects graphs. Just forgetting to set a reference to null or more often forgetting to remove one object from a collection is enough to make a memory leak.

Of course all sort of listeners (like UI listeners), caches, or any long-lived shared state tend to produce memory leak if not properly handled. What shall be understood is that this is not a Java corner case, or a problem with the garbage collector. It is a design problem. We design that we add a listener to a long-lived object, but we don't remove the listener when no longer needed. We cache objects, but we have no strategy to remove them from the cache.

We maybe have a complex graph that store the previous state that is needed by a computation. But the previous state is itself linked to the state before and so on.

Like we have to close SQL connections or files. We need to set proper references to null and remove elements from the collection. We shall have proper caching strategies (maximum memory size, number of elements, or timers). All objects that allow a listener to be notified must provide both a addListener and removeListener method. And when these notifiers are no longer used, they must clear their listener list.

A memory leak is indeed truly possible and is perfectly predictable. No need for special language features or corner cases. Memory leaks are either an indicator that something is maybe missing or even of design problems.

valiano
  • 10,373
  • 4
  • 36
  • 60
Nicolas Bousquet
  • 3,838
  • 1
  • 14
  • 18
  • 32
    I find it funny that on other answers people are looking for those edge cases and tricks and seem to be completely missing the point. They could just show code that keep useless references to objects that will never use again, and never remove those references; one may say those cases are not "true" memory leaks because there are still references to those objects around, but if the program never use those references again and also never drop them, it is completely equivalent to (and as bad as) a "true memory leak". – ehabkost Jul 22 '11 at 06:12
  • @Nicolas Bousquet: *"Memory leak is indeed trully possible"* Thank you so much. +15 upvotes. Nice. I got yelled at here for stating that fact, as the premises of a question about the Go language: http://stackoverflow.com/questions/4400311 This question still has negative downvotes :( – SyntaxT3rr0r Jul 22 '11 at 11:49
  • The GC in Java and .NET is in some sense predicated on the assumption graph of objects that hold references to other objects is the same as the graph of objects that "care about" other objects. In reality, it's possible that edges can exist in the reference graph that don't represent "caring" relations, and it's possible for an object to care about the existence of another object even if no direct or indirect reference path (even using `WeakReference`) exists from one to the other. If a object reference had a spare bit, it could be helpful to have a "cares about the target" indicator... – supercat May 09 '13 at 16:41
  • ...and have the system provide notifications (via means similar to `PhantomReference`) if an object was found not to have anyone that cared about it. `WeakReference` comes somewhat close, but must be converted to a strong reference before it can be used; if a GC cycle occurs while the strong reference exists, the target will be assumed to be useful. – supercat May 09 '13 at 16:47
  • This is in my opinion the correct answer. We wrote a simulation years ago. Somehow we accidentally linked previous state to current state creating a memory leak. Because of a deadline we never resolved the memory leak but made it a «feature» by documenting it. – nalply Apr 18 '17 at 12:16
  • 1
    Agree with this answer. To get into the interviewer's head a bit: there is a connotation among perhaps less-experienced developers, that Java prevents memory leaks (unlike C/C++, for example). So, question for junior developer: how to create a memory leak in Java? There are many ways, and most of them are because of simple carelessness, illustrated nicely above. – Jim Newpower Nov 11 '20 at 16:38
169

The answer depends entirely on what the interviewer thought they were asking.

Is it possible in practice to make Java leak? Of course it is, and there are plenty of examples in the other answers.

But there are multiple meta-questions that may have been being asked?

  • Is a theoretically "perfect" Java implementation vulnerable to leaks?
  • Does the candidate understand the difference between theory and reality?
  • Does the candidate understand how garbage collection works?
  • Or how garbage collection is supposed to work in an ideal case?
  • Do they know they can call other languages through native interfaces?
  • Do they know to leak memory in those other languages?
  • Does the candidate even know what memory management is, and what is going on behind the scene in Java?

I'm reading your meta-question as "What's an answer I could have used in this interview situation". And hence, I'm going to focus on interview skills instead of Java. I believe you're more likely to repeat the situation of not knowing the answer to a question in an interview than you are to be in a place of needing to know how to make Java leak. So, hopefully, this will help.

One of the most important skills you can develop for interviewing is learning to actively listen to the questions and working with the interviewer to extract their intent. Not only does this let you answer their question the way they want, but also shows that you have some vital communication skills. And when it comes down to a choice between many equally talented developers, I'll hire the one who listens, thinks, and understands before they respond every time.

PlayTank
  • 229
  • 1
  • 2
  • 5
  • 24
    Whenever I have asked that question, I am looking for a pretty simple answer - keep growing a queue, no finally close db etc, not odd classloader/thread details, implies they understand what the gc can and cannot do for you. Depends on the job you are interviewing for I guess. – DaveC Jul 03 '11 at 17:59
134

The following is a pretty pointless example, if you do not understand JDBC. Or at least how JDBC expects a developer to close Connection, Statement and ResultSet instances before discarding them or losing references to them, instead of relying on the implementation of finalize.

void doWork()
{
   try
   {
       Connection conn = ConnectionFactory.getConnection();
       PreparedStatement stmt = conn.preparedStatement("some query"); // executes a valid query
       ResultSet rs = stmt.executeQuery();
       while(rs.hasNext())
       {
          ... process the result set
       }
   }
   catch(SQLException sqlEx)
   {
       log(sqlEx);
   }
}

The problem with the above is that the Connection object is not closed, and hence the physical connection will remain open, until the garbage collector comes around and sees that it is unreachable. GC will invoke the finalize method, but there are JDBC drivers that do not implement the finalize, at least not in the same way that Connection.close is implemented. The resulting behavior is that while memory will be reclaimed due to unreachable objects being collected, resources (including memory) associated with the Connection object might simply not be reclaimed.

In such an event where the Connection's finalize method does not clean up everything, one might actually find that the physical connection to the database server will last several garbage collection cycles, until the database server eventually figures out that the connection is not alive (if it does), and should be closed.

Even if the JDBC driver were to implement finalize, it is possible for exceptions to be thrown during finalization. The resulting behavior is that any memory associated with the now "dormant" object will not be reclaimed, as finalize is guaranteed to be invoked only once.

The above scenario of encountering exceptions during object finalization is related to another other scenario that could possibly lead to a memory leak - object resurrection. Object resurrection is often done intentionally by creating a strong reference to the object from being finalized, from another object. When object resurrection is misused it will lead to a memory leak in combination with other sources of memory leaks.

There are plenty more examples that you can conjure up - like

  • Managing a List instance where you are only adding to the list and not deleting from it (although you should be getting rid of elements you no longer need), or
  • Opening Sockets or Files, but not closing them when they are no longer needed (similar to the above example involving the Connection class).
  • Not unloading Singletons when bringing down a Java EE application. Apparently, the Classloader that loaded the singleton class will retain a reference to the class, and hence the singleton instance will never be collected. When a new instance of the application is deployed, a new class loader is usually created, and the former class loader will continue to exist due to the singleton.
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Vineet Reynolds
  • 72,899
  • 16
  • 143
  • 173
  • 103
    You will reach maximum open connection limit before you hit memory limits usually. Don't ask me why I know... – Hardwareguy Jul 21 '11 at 16:23
  • The Oracle JDBC driver is notorious for doing this. – chotchki Aug 20 '13 at 16:06
  • @Hardwareguy I hit the connection limits of the SQL databases a lot until I put `Connection.close` into the finally block of all my SQL calls. For extra fun I called some long running Oracle stored procedures that required locks on the Java side to prevent too many calls to the database. – Michael Shopsin Apr 22 '14 at 14:46
  • @Hardwareguy That is interesting but it is not really necessary that actual connection limits will be hit for all environments. For instance, for an application deployed on weblogic app server 11g I have seen connection leakages at a large scale. But due to a option of harvesting leaked connections database connections remained available while memory leaks were being introduced. I am not sure about all environments. – Aseem Bansal Sep 22 '14 at 18:21
  • In my experience you get a memory leak even if you close the connection. You need to close the ResultSet and PreparedStatement first. Had a server that crashed repeatedly after hours or even days of working fine, due to OutOfMemoryErrors, until I started doing that. – Bjørn Stenfeldt Aug 31 '17 at 08:07
  • Sorry, I am new to Java, so my question may look stupid. Could you please explain "The resulting behavior is that while memory will be reclaimed due to unreachable objects being collected, resources (including memory) associated with the Connection object might simply not be reclaimed"? Do you mean that the memory allocated for the connection object itself will be reclaimed, however, the memory allocated for the resources related to the connection object won't be reclaimed? What exactly do the resources mean? Thanks! – zero_yu Feb 24 '18 at 22:55
  • Assuming that the ConnectionFactory is using a pooled connection, then you would probably use all alloted cursors on the database, because you didn't close the statement. This would most likely happen before you ran out of Java memory. – lafual Nov 03 '20 at 10:41
122

Probably one of the simplest examples of a potential memory leak, and how to avoid it, is the implementation of ArrayList.remove(int):

public E remove(int index) {
    RangeCheck(index);

    modCount++;
    E oldValue = (E) elementData[index];

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index + 1, elementData, index,
                numMoved);
    elementData[--size] = null; // (!) Let gc do its work

    return oldValue;
}

If you were implementing it yourself, would you have thought to clear the array element that is no longer used (elementData[--size] = null)? That reference might keep a huge object alive ...

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
meriton
  • 61,876
  • 13
  • 96
  • 163
  • 5
    And where is the memory leak here? – rds Jul 22 '11 at 16:26
  • 30
    @maniek: I did not mean to imply that this code exhibits a memory leak. I quoted to it to show that sometimes non-obvious code is required to avoid accidental object retention. – meriton Jul 23 '11 at 13:26
  • 1
    What is RangeCheck(index); ? – Koray Tugay Jun 09 '14 at 18:36
  • 6
    Joshua Bloch gave this example in Effective Java showing a simple implementation of Stacks. A very good answer. – rents Jun 27 '15 at 02:22
  • But that would not be a REAL memory leak, even if forgot. The element would still be SAFELLY accessed with Reflection, it would just not be obvious and directly accessible through List interface, but the object and the reference are still there, and can be safelly accessed. – DGoiko May 30 '20 at 14:24
  • Brilliant answer, this is why it's surprisingly easy to leak memory in garbage-collected languages – Andy Feb 04 '21 at 08:02
69

Any time you keep references around to objects that you no longer need you have a memory leak. See Handling memory leaks in Java programs for examples of how memory leaks manifest themselves in Java and what you can do about it.

Bill the Lizard
  • 369,957
  • 201
  • 546
  • 842
  • 15
    I don't believe this is a "leak". It's a bug, and it's by design of the program and language. A leak would be an object hanging around *without* any references to it. – user541686 Jul 02 '11 at 04:31
  • 31
    @Mehrdad: That's only one narrow definition that doesn't fully apply to all languages. I'd argue that *any* memory leak is a bug caused by poor design of the program. – Bill the Lizard Jul 10 '11 at 02:30
  • 2
    I see what you mean (and agree with some of it), but the problem is that if you look at it that way, then the question of "how do you create a memory leak in X?" becomes meaningless, since it's possible in *any* language. So while it may be true, it's not really specific to Java, so I don't think that's what we're referring to as a "leak" here. – user541686 Jul 10 '11 at 03:14
  • 9
    @Mehrdad: `...then the question of "how do you create a memory leak in X?" becomes meaningless, since it's possible in any language.` I don't see how you're drawing that conclusion. There are *fewer* ways to create a memory leak in Java by any definition. It's definitely still a valid question. – Bill the Lizard Jul 10 '11 at 14:09
  • 1
    @Mehrdad, great point, never thought about it that way. In a sense, it's impossible to leak in Java, yet programs can have their memory footprint grow unintentionally. In Objective-C, that problem would NOT be called a memory leak. – Dan Rosenstark Jul 11 '11 at 00:16
  • @Bill the Lizard: I agree--it would still be a valid question, but it becomes worthless. Still meaningful, but worthless. If memory leaks exist when you still have references to objects, *anything* could be considered a memory leak. Like let's say you fire up Minesweeper, but it has been modified so that you can't click the tiles. (I dunno, maybe you like how the board looks.) Because the data under the tiles is now "no longer need"ed, would that memory be a leak? I think not--but your answer implies it would be. – 31eee384 Jul 21 '11 at 18:22
  • 7
    @31eee384: If your program keeps objects in memory that it can never use, then technically it's leaked memory. The fact that you have bigger problems doesn't really change that. – Bill the Lizard Jul 21 '11 at 18:30
  • @Bill the Lizard: According to wikipedia, leaked memory in an OO program is technically "when an object is stored in memory but cannot be accessed by the running code." In my scenario, the object can very well be accessed--it just won't be. (http://en.wikipedia.org/wiki/Memory_leak) – 31eee384 Jul 21 '11 at 18:50
  • 8
    @31eee384: If you know for a fact that it won't be, then it can't be. The program, as written, will never access the data. – Bill the Lizard Jul 21 '11 at 19:13
  • @Bill the Lizard: Seems that it's just a difference of definition then, unfortunately. I think that the first definition of a memory leak on Wikipedia supports me--that a memory leak is "when a computer program consumes memory but is unable to release it back to the operating system". The program can certainly do that, and this extra "leaked" data in Minesweeper will go away when whatever class holds the data is garbage collected. I understand your point, and in a broad sense the data is leaked, however I hold the term "memory leak" to be something more specific, and a more serious problem. – 31eee384 Jul 21 '11 at 20:46
  • @Bill the Lizard: I didn't have enough characters to say it in my previous comment, but I do want to say that I agree with you given how you define memory leak. Given the loose definition, I'd say there are two types of memory leaks: those that are less important, and those that are more important. The lesser are the ones where memory is simply wasted. The greater are the ones where memory isn't retrieved until the JVM is killed. While you consider both types memory leaks, I only consider the latter a leak. – 31eee384 Jul 21 '11 at 20:54
  • 3
    @31eee384: if you keep a reference to an object around and never remove it, the memory won't be retrieved until the JVM is killed, too. Some people won't call it a "true memory leak" because there's a reference somewhere; but if the object is never going to be used again by the program and at the same time the reference will never be dropped by the program either, it is as important as the "true memory leaks" people are looking for as a funny exercise here (or more important, as they are more common than the edge cases people are creating on their answers just to get "true" memory leaks) – ehabkost Jul 22 '11 at 06:09
  • @ehabkost: Yes, I realize the difference. My example isn't like that, though--let's say the data is stored in the Sweeper class. When you start a new game the Sweeper reference is set to null, *the instance is successfully garbage collected*, and the Sweeper reference is assigned a new instance. There is no leakage taking place here. On the other hand, if you had a Vec2f class and managed to accidentally add each instance to some static stack that is never cleared, that would indeed be a memory leak. I find the more apt term for unplayable minesweeper "wasted" memory, instead of "leaked". – 31eee384 Jul 22 '11 at 15:00
  • @ehabkost: In other words, I agree with you too! But I think you are both misrepresenting my scenario as something that it isn't. Another possibly simpler case could be a game with a fatal bug in it, that prevents you from passing a certain stage. Would the further stages, inaccessible but existent, be considered memory leaks? Would a patch that fixes the broken stage be "fixing a memory leak"? I think it's a little silly to use that phrase in that manner. – 31eee384 Jul 22 '11 at 15:04
  • @31eee384: right, I wouldn't call your game stage example a "memory leak". But I think the difference is what is considered the "right behavior" in each case: In your Minesweeper example, the program was supposed to let the user go to the next stages. In other cases, if your program is keeping useless references around when it was supposed to drop them, it is as bad as a "ture memory leak". – ehabkost Jul 22 '11 at 15:44
  • @31eee384: turning your example around: if I have a bug on my C game where I do "next_stage = NULL" by mistake and didn't allow the user to move on, it is technically a "true memory leak", but it would be silly to call it a memory leak because the right fix would be to allow the user to move on, not to free the memory. – ehabkost Jul 22 '11 at 15:45
  • @31eee384 let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/1738/discussion-between-ehabkost-and-31eee384) – ehabkost Jul 22 '11 at 15:45
  • @ehabkost: I was think along similar lines. It's *technically* a memory leak, but there are more useful ways to think about it in order to fix the problem. – Bill the Lizard Jul 22 '11 at 15:59
  • I think this got a bit out of hand... I was originally responding to "any time you keep references around to objects that you no longer *need* you have a memory leak". Specifically, I think I took "need" to mean something more absolute than you meant--rereading your early comments, Bill the Lizard, I find that I actually agree with you. (I also found that I had actually upvoted a few of your comments before I started this mess.) – 31eee384 Jul 22 '11 at 16:22
  • 1
    Boss: "have you found the memory leak?" Programmer: "well we found the bug, but it's not technically a memory leak..." Boss: "then why is the program running out of memory? Just fix the memory leak!" – Andy Feb 04 '21 at 08:06
52

You are able to make memory leak with sun.misc.Unsafe class. In fact this service class is used in different standard classes (for example in java.nio classes). You can't create instance of this class directly, but you may use reflection to do that.

Code doesn't compile in the Eclipse IDE - compile it using command javac (during compilation you'll get warnings)

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import sun.misc.Unsafe;


public class TestUnsafe {

    public static void main(String[] args) throws Exception{
        Class unsafeClass = Class.forName("sun.misc.Unsafe");
        Field f = unsafeClass.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe) f.get(null);
        System.out.print("4..3..2..1...");
        try
        {
            for(;;)
                unsafe.allocateMemory(1024*1024);
        } catch(Error e) {
            System.out.println("Boom :)");
            e.printStackTrace();
        }
    }
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
stemm
  • 5,740
  • 2
  • 29
  • 63
  • 1
    Allocated memory is invisible for garbage collector – stemm Jul 11 '11 at 15:32
  • 4
    The allocated memory doesn't belong to Java either. – bestsss Jul 17 '11 at 18:35
  • Is this sun/oracle jvm specific? E.g. will this work on IBM? – Berlin Brown Jul 21 '11 at 16:40
  • @Berlin Brow In fact I've didn't work with jvm of IBM. But as I told - some standart packages (java.nio, java.util.concurrent etc.) use this service class. So if IBMs jvm supports usage of these libraries, probably it has native code to cope with sun.misc.Unsafe – stemm Jul 22 '11 at 13:50
  • 2
    The memory certainly does "belong to Java", at least in the sense that i) its not available to anyone else, ii) when the Java application exits it will be returned to the system. It is just outside the JVM. – Michael Anderson Jun 02 '16 at 03:19
  • 3
    This will build in eclipse (at least in recent versions) but you'll need to change the compiler settings: in Window > Preferences > Java > Compiler > Errors/Warning > Deprecated and restricted API set Forbidden reference (access rules) to "Warning". – Michael Anderson Jun 02 '16 at 03:21
  • Strongly advise readers to consider that IDE specific behaviors in developing code is not only irrelevant but dangerous. Namely, system stability and consistency demands a singular, consistent compiler. An IDE generally uses "javac" of some version from some vendor/impl. Consistency in runtime behavior within a given JVM relies on having the same byte-code interpretation. Since servers do not run IDEs or their (as likely instrumented) run-time environments, it is dangerous to make any presumptions or cases around what a given IDE does or doesn't do. Reference the javac instance and JVM only. – Darrell Teague Apr 03 '18 at 18:58
43

I can copy my answer from here: Easiest way to cause memory leak in Java

"A memory leak, in computer science (or leakage, in this context), occurs when a computer program consumes memory but is unable to release it back to the operating system." (Wikipedia)

The easy answer is: You can't. Java does automatic memory management and will free resources that are not needed for you. You can't stop this from happening. It will always be able to release the resources. In programs with manual memory management, this is different. You can get some memory in C using malloc(). To free the memory, you need the pointer that malloc returned and call free() on it. But if you don't have the pointer any more (overwritten, or lifetime exceeded), then you are unfortunately incapable of freeing this memory and thus you have a memory leak.

All the other answers so far are in my definition not really memory leaks. They all aim at filling the memory with pointless stuff real fast. But at any time you could still dereference the objects you created and thus freeing the memory --> no leak. acconrad's answer comes pretty close though as I have to admit since his solution is effectively to just "crash" the garbage collector by forcing it in an endless loop).

The long answer is: You can get a memory leak by writing a library for Java using the JNI, which can have manual memory management and thus have memory leaks. If you call this library, your Java process will leak memory. Or, you can have bugs in the JVM, so that the JVM looses memory. There are probably bugs in the JVM, there may even be some known ones since garbage collection is not that trivial, but then it's still a bug. By design this is not possible. You may be asking for some Java code that is effected by such a bug. Sorry I don't know one and it might well not be a bug any more in the next Java version anyway.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
yankee
  • 32,900
  • 12
  • 87
  • 147
  • 14
    That's an extremely limited (and not very useful) definition of memory leaks. The only definition that makes sense for practical purposes is "a memory leak is any condition in which the program continues to hold memory allocated after the data it holds it is no longer needed." – Mason Wheeler Jan 23 '14 at 19:54
  • 1
    The mentioned acconrad's answer was deleted? – Tomáš Zato - Reinstate Monica Jan 05 '16 at 08:36
  • 1
    @TomášZato: No it's not. I turned the reference above to link now, so you can easily find it. – yankee Jan 05 '16 at 11:14
  • What is object resurrection? How many times does a destructor get called? How do these questions disprove this answer? – autistic Dec 06 '16 at 17:08
  • 1
    Well, sure you can create a memory leak inside Java, despite GC, and still fulfill the above definition. Just have an append-only data structure, protected against external access so that no other code every removes it - the program cannot release the memory because it does not have the code. – toolforger Nov 03 '18 at 23:37
  • Knowing Java will free resources that aren't needed sounds like complete safety. But then you run into out of memory errors in production and realize stuff that isn't needed can easily get left in places the GC won't free it. Java can't know if something in a static variable will be needed later. – Andy Feb 04 '21 at 07:42
  • "at any time you could still dereference the objects you created" - you could if you edit the code, but at runtime, if no code path will dereference those objects, it's literally impossible to free them – Andy Feb 04 '21 at 07:45
39

Here's a simple/sinister one via http://wiki.eclipse.org/Performance_Bloopers#String.substring.28.29.

public class StringLeaker
{
    private final String muchSmallerString;

    public StringLeaker()
    {
        // Imagine the whole Declaration of Independence here
        String veryLongString = "We hold these truths to be self-evident...";

        // The substring here maintains a reference to the internal char[]
        // representation of the original string.
        this.muchSmallerString = veryLongString.substring(0, 1);
    }
}

Because the substring refers to the internal representation of the original, much longer string, the original stays in memory. Thus, as long as you have a StringLeaker in play, you have the whole original string in memory, too, even though you might think you're just holding on to a single-character string.

The way to avoid storing an unwanted reference to the original string is to do something like this:

...
this.muchSmallerString = new String(veryLongString.substring(0, 1));
...

For added badness, you might also .intern() the substring:

...
this.muchSmallerString = veryLongString.substring(0, 1).intern();
...

Doing so will keep both the original long string and the derived substring in memory even after the StringLeaker instance has been discarded.

Jon Chambers
  • 604
  • 7
  • 13
  • 4
    I wouldn't call that a memory leak, _per se_. When `muchSmallerString` is freeed (because the `StringLeaker` object is destroyed), the long string will be freed as well. What I call memory leak is memory that can never been freeed in this instance of JVM. However, you have shown yourself how to free the memory: `this.muchSmallerString=new String(this.muchSmallerString)`. With a real memory leak, there is nothing you can do. – rds Jul 22 '11 at 16:45
  • 2
    @rds, that's a fair point. The non-`intern` case may be more of a "memory surprise" than a "memory leak." `.intern()`ing the substring, though, certainly creates a situation where the reference to the longer string is preserved and cannot be freed. – Jon Chambers Jul 22 '11 at 18:42
  • 17
    The method substring() creates a new String in java7 (it is a new behavior) – anstarovoyt Mar 22 '13 at 12:43
  • You don't even need to do the substring() yourself: Use a regex matcher to match a tiny part of a huge input, and carry the "extracted" string around for a long time. The huge input stays alive up to Java 6. – Bananeweizen Oct 04 '17 at 16:46
37

A common example of this in GUI code is when creating a widget/component and adding a listener to some static/application scoped object and then not removing the listener when the widget is destroyed. Not only do you get a memory leak, but also a performance hit as when whatever you are listening to fires events, all your old listeners are called too.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
pillingworth
  • 3,128
  • 2
  • 21
  • 46
  • 1
    The android platform gives the exemple of a memory leak created by [caching a Bitmap in the static field of a View](http://developer.android.com/resources/articles/avoiding-memory-leaks.html). – rds Jul 22 '11 at 16:34
36

Maybe by using external native code through JNI?

With pure Java, it is almost impossible.

But that is about a "standard" type of memory leak, when you cannot access the memory anymore, but it is still owned by the application. You can instead keep references to unused objects, or open streams without closing them afterwards.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Rogach
  • 22,915
  • 19
  • 81
  • 160
  • 23
    That depends on the definition of "memory leak". If "memory that's held on to, but no longer needed", then it's easy to do in Java. If it's "memory that's allocated but not accessible by the code at all", then it gets slightly harder. – Joachim Sauer Jun 24 '11 at 16:15
  • @Joachim Sauer - I meant the second type. The first is fairly easy to make :) – Rogach Jun 24 '11 at 16:17
  • 6
    "With pure java, it is almost impossible." Well, my experience is another especially when it comes to implementing caches by people that are not aware of the pitfalls here. – Fabian Barney Jun 24 '11 at 16:28
  • 4
    @Rogach: there are basically +400 upvotes on various answers by people with +10 000 rep showing that in both the cases *Joachim Sauer* commented it's very possible. So your "almost impossible" makes no sense. – SyntaxT3rr0r Jul 22 '11 at 11:51
36

Take any web application running in any servlet container (Tomcat, Jetty, GlassFish, whatever...). Redeploy the application 10 or 20 times in a row (it may be enough to simply touch the WAR in the server's autodeploy directory.

Unless anybody has actually tested this, chances are high that you'll get an OutOfMemoryError after a couple of redeployments, because the application did not take care to clean up after itself. You may even find a bug in your server with this test.

The problem is, the lifetime of the container is longer than the lifetime of your application. You have to make sure that all references the container might have to objects or classes of your application can be garbage collected.

If there is just one reference surviving the undeployment of your web application, the corresponding classloader and by consequence all classes of your web application cannot be garbage collected.

Threads started by your application, ThreadLocal variables, logging appenders are some of the usual suspects to cause classloader leaks.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Harald Wellmann
  • 11,788
  • 2
  • 36
  • 56
  • 1
    This is not because of a memory leak, but because the class loader does not unload the previous set of classes. Therefor it is not recommended to redeploy an application server without restarting the server (not the physical machine, but the app server). I have seen the same issue with WebSphere. – Sven May 22 '18 at 05:23
32

I have had a nice "memory leak" in relation to PermGen and XML parsing once. The XML parser we used (I can't remember which one it was) did a String.intern() on tag names, to make comparison faster. One of our customers had the great idea to store data values not in XML attributes or text, but as tagnames, so we had a document like:

<data>
   <1>bla</1>
   <2>foo</>
   ...
</data>

In fact, they did not use numbers but longer textual IDs (around 20 characters), which were unique and came in at a rate of 10-15 million a day. That makes 200 MB of rubbish a day, which is never needed again, and never GCed (since it is in PermGen). We had permgen set to 512 MB, so it took around two days for the out-of-memory exception (OOME) to arrive...

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Ron
  • 682
  • 6
  • 7
  • 4
    Just to nitpick your example code: I think numbers (or strings starting with numbers) are not allowed as element names in XML. – Paŭlo Ebermann Jul 03 '11 at 00:18
  • Note that this is no longer true for JDK 7+, where String interning happens on the heap. See this article for a detailed writeup: http://java-performance.info/string-intern-in-java-6-7-8/ – jmiserez Apr 18 '17 at 19:47
  • So, i think using StringBuffer in place of String would resolve this problem? wont it? – anubhs Jun 02 '20 at 17:03
25

What's a memory leak:

  • It's caused by a bug or bad design.
  • It's a waste of memory.
  • It gets worse over time.
  • The garbage collector cannot clean it.

Typical example:

A cache of objects is a good starting point to mess things up.

private static final Map<String, Info> myCache = new HashMap<>();

public void getInfo(String key)
{
    // uses cache
    Info info = myCache.get(key);
    if (info != null) return info;

    // if it's not in cache, then fetch it from the database
    info = Database.fetch(key);
    if (info == null) return null;

    // and store it in the cache
    myCache.put(key, info);
    return info;
}

Your cache grows and grows. And pretty soon the entire database gets sucked into memory. A better design uses an LRUMap (Only keeps recently used objects in cache).

Sure, you can make things a lot more complicated:

  • using ThreadLocal constructions.
  • adding more complex reference trees.
  • or leaks caused by 3rd party libraries.

What often happens:

If this Info object has references to other objects, which again have references to other objects. In a way you could also consider this to be some kind of memory leak, (caused by bad design).

bvdb
  • 15,306
  • 3
  • 82
  • 95
  • On a slightly unrelated note: There's a popular saying: There are only 2 things difficult in programming: naming things and cache invalidation. – bvdb May 03 '21 at 15:02
22

The interviewer was probably looking for a circular reference like the code below (which incidentally only leak memory in very old JVMs that used reference counting, which isn't the case any more). But it's a pretty vague question, so it's a prime opportunity to show off your understanding of JVM memory management.

class A {
    B bRef;
}

class B {
    A aRef;
}

public class Main {
    public static void main(String args[]) {
        A myA = new A();
        B myB = new B();
        myA.bRef = myB;
        myB.aRef = myA;
        myA=null;
        myB=null;
        /* at this point, there is no access to the myA and myB objects, */
        /* even though both objects still have active references. */
    } /* main */
}

Then you can explain that with reference counting, the above code would leak memory. But most modern JVMs don't use reference counting any longer. Most use a sweep garbage collector, which will in fact collect this memory.

Next you might explain creating an Object that has an underlying native resource, like this:

public class Main {
    public static void main(String args[]) {
        Socket s = new Socket(InetAddress.getByName("google.com"),80);
        s=null;
        /* at this point, because you didn't close the socket properly, */
        /* you have a leak of a native descriptor, which uses memory. */
    }
}

Then you can explain this is technically a memory leak, but really the leak is caused by native code in the JVM allocating underlying native resources, which weren't freed by your Java code.

At the end of the day, with a modern JVM, you need to write some Java code that allocates a native resource outside the normal scope of the JVM's awareness.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
deltamind106
  • 502
  • 4
  • 16
22

I thought it was interesting that no one used the internal class examples. If you have an internal class; it inherently maintains a reference to the containing class. Of course it is not technically a memory leak because Java WILL eventually clean it up; but this can cause classes to hang around longer than anticipated.

public class Example1 {
  public Example2 getNewExample2() {
    return this.new Example2();
  }
  public class Example2 {
    public Example2() {}
  }
}

Now if you call Example1 and get an Example2 discarding Example1, you will inherently still have a link to an Example1 object.

public class Referencer {
  public static Example2 GetAnExample2() {
    Example1 ex = new Example1();
    return ex.getNewExample2();
  }

  public static void main(String[] args) {
    Example2 ex = Referencer.GetAnExample2();
    // As long as ex is reachable; Example1 will always remain in memory.
  }
}

I've also heard a rumor that if you have a variable that exists for longer than a specific amount of time; Java assumes that it will always exist and will actually never try to clean it up if cannot be reached in code anymore. But that is completely unverified.

Suroot
  • 4,155
  • 1
  • 19
  • 28
  • 2
    inner classes are rarely an issue. They are a straightforward case and very easy to detect. The rumor is just a rumor too. – bestsss Jul 09 '11 at 06:54
  • 2
    The "rumor" sounds like someone half-read about how generational GC works. Long-lived-but-now-unreachable objects can indeed stick around and take up space for a while, because the JVM promoted them out of the younger generations so it could stop checking them every pass. They will evade the piddly "clean up my 5000 temp strings" passes, by design. But they're not immortal. They're still eligible for collection, and if the VM is strapped for RAM, it will eventually run a full GC sweep and repossess that memory. – cHao Aug 16 '13 at 20:33
22

I recently encountered a memory leak situation caused in a way by log4j.

Log4j has this mechanism called Nested Diagnostic Context(NDC) which is an instrument to distinguish interleaved log output from different sources. The granularity at which NDC works is threads, so it distinguishes log outputs from different threads separately.

In order to store thread specific tags, log4j's NDC class uses a Hashtable which is keyed by the Thread object itself (as opposed to say the thread id), and thus till the NDC tag stays in memory all the objects that hang off of the thread object also stay in memory. In our web application we use NDC to tag logoutputs with a request id to distinguish logs from a single request separately. The container that associates the NDC tag with a thread, also removes it while returning the response from a request. The problem occurred when during the course of processing a request, a child thread was spawned, something like the following code:

pubclic class RequestProcessor {
    private static final Logger logger = Logger.getLogger(RequestProcessor.class);
    public void doSomething()  {
        ....
        final List<String> hugeList = new ArrayList<String>(10000);
        new Thread() {
           public void run() {
               logger.info("Child thread spawned")
               for(String s:hugeList) {
                   ....
               }
           }
        }.start();
    }
}    

So an NDC context was associated with inline thread that was spawned. The thread object that was the key for this NDC context, is the inline thread which has the hugeList object hanging off of it. Hence even after the thread finished doing what it was doing, the reference to the hugeList was kept alive by the NDC context Hastable, thus causing a memory leak.

Puneet
  • 686
  • 8
  • 16
  • That sucks. You should check this logging library that allocates ZERO memory while logging to a file: http://mentalog.soliveirajr.com – TraderJoeChicago Sep 20 '11 at 23:10
  • +1 Do you know offhand whether there is a similar issue with the MDC in slf4j/logback (successor products by the same author)? I'm about to do a deep dive on the source but wanted to check first. Either way, thanks for posting this. – sparc_spread Jul 02 '14 at 21:40
20

Create a static Map and keep adding hard references to it. Those will never be garbage collected.

public class Leaker {
    private static final Map<String, Object> CACHE = new HashMap<String, Object>();

    // Keep adding until failure.
    public static void addToCache(String key, Object value) { Leaker.CACHE.put(key, value); }
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
duffymo
  • 293,097
  • 41
  • 348
  • 541
  • 91
    How is that a leak? It's doing exactly what you're asking it to do. If that's a leak, creating and storing objects anywhere is a leak. – Falmarri Jul 21 '11 at 19:10
  • 3
    I agree with @Falmarri. I don't see a leak there, you are just creating objects. You could certainly 'reclaim' the memory that you just allocated with another method called 'removeFromCache'. A leak is when you can't reclaim the memory. – Kyle Jul 17 '12 at 19:08
  • 4
    My point is that somebody who keeps creating objects, perhaps putting them into a cache, could end up with an OOM error if they aren't careful. – duffymo Jul 17 '12 at 20:07
  • 8
    @duffymo: But that's not really what the question was asking. It has nothing to do with simply using up all your memory. – Falmarri Jul 18 '12 at 22:10
  • 3
    Absolutely invalid. You are just collecting a bunch of objects in a Map collection. Their references will be kept because the Map holds them. – gyorgyabraham Nov 29 '13 at 10:36
  • 3
    This is the classic memory leak in Java. It is not a leak in the sense of the JVM has lost track of the memory, but it is a leak in the sense that the JVM will never garbage collect it. If you monitor the heap of an application that uses this construct it will have a generally increasing trend and will eventually terminate with OutOfMemoryError. That is the definition of a memory leak. – sceaj Nov 28 '17 at 22:59
  • 5
    The comments dissing this answer are pretty funny, given that the accepted answer with over 2000 votes is saying the exact same thing, albeit in a highly obfuscated way. ThreadLocals aren't magic -- they are just entries in a Map, pointed to by a member variable in Thread. – Ernest Friedman-Hill Jan 03 '19 at 14:09
19

Everyone always forgets the native code route. Here's a simple formula for a leak:

  1. Declare a native method.
  2. In the native method, call malloc. Don't call free.
  3. Call the native method.

Remember, memory allocations in native code come from the JVM heap.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Paul Morie
  • 14,690
  • 9
  • 50
  • 57
16

You can create a moving memory leak by creating a new instance of a class in that class's finalize method. Bonus points if the finalizer creates multiple instances. Here's a simple program that leaks the entire heap in sometime between a few seconds and a few minutes depending on your heap size:

class Leakee {
    public void check() {
        if (depth > 2) {
            Leaker.done();
        }
    }
    private int depth;
    public Leakee(int d) {
        depth = d;
    }
    protected void finalize() {
        new Leakee(depth + 1).check();
        new Leakee(depth + 1).check();
    }
}

public class Leaker {
    private static boolean makeMore = true;
    public static void done() {
        makeMore = false;
    }
    public static void main(String[] args) throws InterruptedException {
        // make a bunch of them until the garbage collector gets active
        while (makeMore) {
            new Leakee(0).check();
        }
        // sit back and watch the finalizers chew through memory
        while (true) {
            Thread.sleep(1000);
            System.out.println("memory=" +
                    Runtime.getRuntime().freeMemory() + " / " +
                    Runtime.getRuntime().totalMemory());
        }
    }
}
sethobrien
  • 949
  • 6
  • 13
15

I came across a more subtle kind of resource leak recently. We open resources via class loader's getResourceAsStream and it happened that the input stream handles were not closed.

Uhm, you might say, what an idiot.

Well, what makes this interesting is: this way, you can leak heap memory of the underlying process, rather than from JVM's heap.

All you need is a jar file with a file inside which will be referenced from Java code. The bigger the jar file, the quicker memory gets allocated.

You can easily create such a jar with the following class:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class BigJarCreator {
    public static void main(String[] args) throws IOException {
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File("big.jar")));
        zos.putNextEntry(new ZipEntry("resource.txt"));
        zos.write("not too much in here".getBytes());
        zos.closeEntry();
        zos.putNextEntry(new ZipEntry("largeFile.out"));
        for (int i=0 ; i<10000000 ; i++) {
            zos.write((int) (Math.round(Math.random()*100)+20));
        }
        zos.closeEntry();
        zos.close();
    }
}

Just paste into a file named BigJarCreator.java, compile and run it from command line:

javac BigJarCreator.java
java -cp . BigJarCreator

Et voilà: you find a jar archive in your current working directory with two files inside.

Let's create a second class:

public class MemLeak {
    public static void main(String[] args) throws InterruptedException {
        int ITERATIONS=100000;
        for (int i=0 ; i<ITERATIONS ; i++) {
            MemLeak.class.getClassLoader().getResourceAsStream("resource.txt");
        }
        System.out.println("finished creation of streams, now waiting to be killed");

        Thread.sleep(Long.MAX_VALUE);
    }

}

This class basically does nothing, but create unreferenced InputStream objects. Those objects will be garbage collected immediately and thus, do not contribute to heap size. It is important for our example to load an existing resource from a jar file, and size does matter here!

If you're doubtful, try to compile and start the class above, but make sure to chose a decent heap size (2 MB):

javac MemLeak.java
java -Xmx2m -classpath .:big.jar MemLeak

You will not encounter an OOM error here, as no references are kept, the application will keep running no matter how large you chose ITERATIONS in the above example. The memory consumption of your process (visible in top (RES/RSS) or process explorer) grows unless the application gets to the wait command. In the setup above, it will allocate around 150 MB in memory.

If you want the application to play safe, close the input stream right where it's created:

MemLeak.class.getClassLoader().getResourceAsStream("resource.txt").close();

and your process will not exceed 35 MB, independent of the iteration count.

Quite simple and surprising.

Jay
  • 11
  • 2
  • 6
15

I don't think anyone has said this yet: you can resurrect an object by overriding the finalize() method such that finalize() stores a reference of this somewhere. The garbage collector will only be called once on the object so after that the object will never destroyed.

Ben
  • 2,240
  • 3
  • 20
  • 24
  • 10
    This is untrue. `finalize()` will not be called but the object will be collected once there won't be more references. Garbage collector is not 'called' either. – bestsss Jul 05 '11 at 19:38
  • 1
    This answer is misleading, the `finalize()` method can only be called once by the JVM, but this does not mean that it cannot be re-garbage collected if the object is resurrected and then dereferenced again. If there is resource closing code in the `finalize()` method then this code will not get run again, this may cause a memory leak. – Tom Cammann Dec 19 '12 at 11:36
14

Another way to create potentially huge memory leaks is to hold references to Map.Entry<K,V> of a TreeMap.

It is hard to asses why this applies only to TreeMaps, but by looking at the implementation the reason might be that: a TreeMap.Entry stores references to its siblings, therefore if a TreeMap is ready to be collected, but some other class holds a reference to any of its Map.Entry, then the entire Map will be retained into memory.


Real-life scenario:

Imagine having a db query that returns a big TreeMap data structure. People usually use TreeMaps as the element insertion order is retained.

public static Map<String, Integer> pseudoQueryDatabase();

If the query was called lots of times and, for each query (so, for each Map returned) you save an Entry somewhere, the memory would constantly keep growing.

Consider the following wrapper class:

class EntryHolder {
    Map.Entry<String, Integer> entry;

    EntryHolder(Map.Entry<String, Integer> entry) {
        this.entry = entry;
    }
}

Application:

public class LeakTest {

    private final List<EntryHolder> holdersCache = new ArrayList<>();
    private static final int MAP_SIZE = 100_000;

    public void run() {
        // create 500 entries each holding a reference to an Entry of a TreeMap
        IntStream.range(0, 500).forEach(value -> {
            // create map
            final Map<String, Integer> map = pseudoQueryDatabase();

            final int index = new Random().nextInt(MAP_SIZE);

            // get random entry from map
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                if (entry.getValue().equals(index)) {
                    holdersCache.add(new EntryHolder(entry));
                    break;
                }
            }
            // to observe behavior in visualvm
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

    }

    public static Map<String, Integer> pseudoQueryDatabase() {
        final Map<String, Integer> map = new TreeMap<>();
        IntStream.range(0, MAP_SIZE).forEach(i -> map.put(String.valueOf(i), i));
        return map;
    }

    public static void main(String[] args) throws Exception {
        new LeakTest().run();
    }
}

After each pseudoQueryDatabase() call, the map instances should be ready for collection, but it won't happen, as at least one Entry is stored somewhere else.

Depending on your jvm settings, the application may crash in the early stage due to a OutOfMemoryError.

You can see from this visualvm graph how the memory keeps growing.

Memory dump - TreeMap

The same does not happen with a hashed data-structure (HashMap).

This is the graph when using a HashMap.

Memory dump - HashMap

The solution? Just directly save the key / value (as you probably already do) rather than saving the Map.Entry.


I have written a more extensive benchmark here.

Marko Pacak
  • 3,381
  • 1
  • 9
  • 37
14

As a lot of people have suggested, resource leaks are fairly easy to cause - like the JDBC examples. Actual memory leaks are a bit harder - especially if you aren't relying on broken bits of the JVM to do it for you...

The ideas of creating objects that have a very large footprint and then not being able to access them aren't real memory leaks either. If nothing can access it then it will be garbage collected, and if something can access it then it's not a leak...

One way that used to work though - and I don't know if it still does - is to have a three-deep circular chain. As in Object A has a reference to Object B, Object B has a reference to Object C and Object C has a reference to Object A. The GC was clever enough to know that a two deep chain - as in A <--> B - can safely be collected if A and B aren't accessible by anything else, but couldn't handle the three-way chain...

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Graham
  • 3,609
  • 3
  • 27
  • 30
11

Threads are not collected until they terminate. They serve as roots of garbage collection. They are one of the few objects that won't be reclaimed simply by forgetting about them or clearing references to them.

Consider: the basic pattern to terminate a worker thread is to set some condition variable seen by the thread. The thread can check the variable periodically and use that as a signal to terminate. If the variable is not declared volatile, then the change to the variable might not be seen by the thread, so it won't know to terminate. Or imagine if some threads want to update a shared object, but deadlock while trying to lock on it.

If you only have a handful of threads these bugs will probably be obvious because your program will stop working properly. If you have a thread pool that creates more threads as needed, then the obsolete/stuck threads might not be noticed, and will accumulate indefinitely, causing a memory leak. Threads are likely to use other data in your application, so will also prevent anything they directly reference from ever being collected.

As a toy example:

static void leakMe(final Object object) {
    new Thread() {
        public void run() {
            Object o = object;
            for (;;) {
                try {
                    sleep(Long.MAX_VALUE);
                } catch (InterruptedException e) {}
            }
        }
    }.start();
}

Call System.gc() all you like, but the object passed to leakMe will never die.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Boann
  • 44,932
  • 13
  • 106
  • 138
  • 1
    @Spidey Nothing is "stuck". The calling method returns promptly, and the passed object will never be reclaimed. That's precisely a leak. – Boann Sep 26 '13 at 23:39
  • 1
    You'll have a thread "running" (or sleeping, whatever) for the lifetime of your program. That doesn't count as a leak to me. As well as a pool doesn't count as a leak, even if you don't use it entirely. – Spidey Sep 27 '13 at 01:24
  • 1
    @Spidey "You'll have a [thing] for the lifetime of your program. That doesn't count as a leak to me." Do you hear yourself? – Boann Sep 27 '13 at 01:39
  • Yes I do. The process still references the thread, and the thread still references the `o` object. You may have misunderstood what a memory leak is. – Spidey Sep 27 '13 at 15:51
  • 3
    @Spidey If you would count memory that the process knows about as not being leaked, then all the answers here are wrong, since the process always tracks which pages in its virtual address space are mapped. When the process terminates, the OS cleans up all the leaks by putting the pages back on the free page stack. To take that to the next extreme, one could beat to death any argued leak by pointing out that none of the physical bits in the RAM chips or in the swap space on disk have been physically misplaced or destroyed, so you can switch the computer off and on again to clean up any leak. – Boann Sep 27 '13 at 18:00
  • 1
    The practical definition of a leak is that it's memory which has been lost track of such that we don't know and thus can't perform the procedure necessary to reclaim only it; we would have to tear down and rebuild the entire memory space. A rogue thread like this could arise naturally through a deadlock or dodgy threadpool implementation. Objects referenced by such threads, even indirectly, are now prevented from ever being collected, so we have memory which will not be naturally reclaimed or reusable during the lifetime of the program. I'd call that a problem; specifically it's a memory leak. – Boann Sep 27 '13 at 18:00
  • @Spidey What is your answer? What do you consider a leak? – Boann Oct 01 '13 at 18:17
  • Since Java has a garbage collector, I don't think it can even leak. – Spidey Oct 02 '13 at 14:06
  • @Spidey Then try it for yourself and you'll see that it does leak. The garbage collector isn't (and cannot be) infallible because it can't tell the difference between live references and obsolete ones, which is why explicit nulling of obsolete references is necessary when the object or scope holding the obsolete reference is still in use. – Boann Oct 02 '13 at 14:22
  • There is no difference between "live references and obsolete ones" in the context of the question. They are still referenced somewhere. In a C program, a leak isn't referenced anywhere, even the OS can't touch it. It can release all memory pages used by a given process, but it can't reference each and every memory block allocated. – Spidey Oct 02 '13 at 18:07
  • @Spidey It's the most important difference. At a lower level (program -> JVM -> OS -> RAM chips -> Universe) any memory leak from the higher level becomes unreal. The practical definition for a memory leak is that during execution, your memory space (at whatever level you define it) is accumulating things which are not wanted, reducing available space for things which are wanted. "In a C program, a leak isn't referenced anywhere" -- also wrong -- leaked memory could still be referenced. What matters is whether the memory can be re-used, which in C does not depend on whether it's referenced. – Boann Oct 02 '13 at 19:36
  • obviously not much people think you are right. See this: http://www.ibm.com/developerworks/rational/library/05/0816_GuptaPalanki/ Memory leaks in Java are not real leaks, they are bad design choices or bugs in code. – Spidey Oct 02 '13 at 23:19
  • @Spidey "not much people think you are right".. Uh, about which? Which people? Where? Check the previous page of answers for the many older, popular answers that I'm defending here and which you are calling wrong. "Memory leaks in Java are not real leaks" Nowhere does the article say that. It gives examples of memory leaks and shows how they are a real loss of usable memory due to objects not being reclaimed. Those objects accumulate over time and become a real problem. That's what a memory leak is. "they are bad design choices or bugs in code" ... which result in **memory leaks**, yes. – Boann Oct 03 '13 at 16:14
  • I mean all the people who read your answer and our discussion, and still didn't care to up or down your post. But that's not a real argument anyway. See slowlyLeakingVector in Listing 2. I could accept that as a memory leak, but that's different from what you are doing. As I see, your answer suggests that any unused allocated object implies in a leak. I don't agree with that. – Spidey Oct 03 '13 at 17:23
  • This is totally valid code, it's what it means to use threads. They are designed to keep their references. Also it's not only threads that do this, also GUI frames keep everything referenced by them even though there is no thread. There are a few other "tops" to the GC tree as well. If you have a thread that runs forever then, by design, it will keep everything it references forever, otherwise nothing will work. If this is not what you intended however, then you DO have a programming bug! – Bill K Oct 03 '13 at 22:02
  • 1
    @Spidey "I could accept that as a memory leak" Thank you. Earlier, you'd said something couldn't be a leak if it's still referenced and that you couldn't have a leak in Java because it has a garbage collector. >_< "Your answer suggests that any unused allocated object implies a leak". Well, the example is a scenario of an object that the garbage collector can't/won't collect. If it emerges in a program and happens repeatedly it becomes a leak. I'll try to improve my answer with that info. – Boann Oct 04 '13 at 04:30
  • Can't you just allocate a bunch of memory on background threads and intentionally deadlock them by using a very poorly structured system of nested thread locks? It fits the profile of running for the life of the program and not being accessible by the application or recoverable by the GC. – Evan Plaice Feb 24 '14 at 10:08
11

The interviewer might have been looking for a circular reference solution:

    public static void main(String[] args) {
        while (true) {
            Element first = new Element();
            first.next = new Element();
            first.next.next = first;
        }
    }

This is a classic problem with reference counting garbage collectors. You would then politely explain that JVMs use a much more sophisticated algorithm that doesn't have this limitation.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Wesley Tarle
  • 638
  • 3
  • 6
  • 13
    *This is a classic problem with reference counting garbage collectors.* Even 15 years ago Java didn't use ref counting. Ref. counting is also slower than GC. – bestsss Jul 05 '11 at 19:36
  • 5
    Not a memory leak. Just an infinite loop. – Esben Skov Pedersen Jul 21 '11 at 15:15
  • 2
    @Esben At each iteration, the previous `first` is not useful and should be garbage collected. In _reference counting_ garbage collectors, the object wouldn't be freeed because there is an active reference on it (by itself). The infinite loop is here to desmonstrate the leak: when you run the program, the memory will raise indefinitely. – rds Jul 22 '11 at 16:37
  • @rds @ Wesley Tarle suppose the loop was *not* infinite. Would there still be a memory leak? – nz_21 Nov 06 '18 at 15:55
10

I think that a valid example could be using ThreadLocal variables in an environment where threads are pooled.

For instance, using ThreadLocal variables in Servlets to communicate with other web components, having the threads being created by the container and maintaining the idle ones in a pool. ThreadLocal variables, if not correctly cleaned up, will live there until, possibly, the same web component overwrites their values.

Of course, once identified, the problem can be solved easily.

Martín Schonaker
  • 7,022
  • 4
  • 28
  • 55
10

There are many different situations memory will leak. One I encountered, which expose a map that should not be exposed and used in other place.

public class ServiceFactory {

    private Map<String, Service> services;

    private static ServiceFactory singleton;

    private ServiceFactory() {
        services = new HashMap<String, Service>();
    }

    public static synchronized ServiceFactory getDefault() {

        if (singleton == null) {
            singleton = new ServiceFactory();
        }
        return singleton;
    }

    public void addService(String name, Service serv) {
        services.put(name, serv);
    }

    public void removeService(String name) {
        services.remove(name);
    }

    public Service getService(String name, Service serv) {
        return services.get(name);
    }

    // The problematic API, which exposes the map.
    // and user can do quite a lot of thing from this API.
    // for example, create service reference and forget to dispose or set it null
    // in all this is a dangerous API, and should not expose
    public Map<String, Service> getAllServices() {
        return services;
    }

}

// Resource class is a heavy class
class Service {

}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Ben Xu
  • 1,209
  • 2
  • 13
  • 24
9

An example I recently fixed is creating new GC and Image objects, but forgetting to call dispose() method.

GC javadoc snippet:

Application code must explicitly invoke the GC.dispose() method to release the operating system resources managed by each instance when those instances are no longer required. This is particularly important on Windows95 and Windows98 where the operating system has a limited number of device contexts available.

Image javadoc snippet:

Application code must explicitly invoke the Image.dispose() method to release the operating system resources managed by each instance when those instances are no longer required.

Scott
  • 1
  • 1
8

A thread that does not terminate (say sleeps indefinitely in its run method). It will not be garbage collected even if we lose a reference to it. You can add fields to make the thread object is a big as you want.

The currently top answer lists more tricks around this, but these seem redundant.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Audrius Meskauskas
  • 18,378
  • 9
  • 63
  • 78
8

I want to give advice on how to monitor an application for the memory leaks with the tools that are available in the JVM. It doesn't show how to generate the memory leak, but explains how to detect it with the minimum tools available.

You need to monitor Java memory consumption first.

The simplest way to do this is to use the jstat utility that comes with JVM:

jstat -gcutil <process_id> <timeout>

It will report memory consumption for each generation (young, eldery and old) and garbage collection times (young and full).

As soon as you spot that a full garbage collection is executed too often and takes too much time, you can assume that application is leaking memory.

Then you need to create a memory dump using the jmap utility:

jmap -dump:live,format=b,file=heap.bin <process_id>

Then you need to analyse the heap.bin file with a memory analyser, Eclipse Memory Analyzer (MAT) for example.

MAT will analyze the memory and provide you suspect information about memory leaks.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Pavel Molchanov
  • 1,874
  • 15
  • 19
8

Theoretically you can't. The Java memory model prevents it. However, because Java has to be implemented, there are some caveats you can use. It depends on what you can use:

  • If you can use native, you can allocate memory that you do not relinquish later.

  • If that is not available, there is a dirty little secret about Java that not much people know. You can ask for a direct access array that is not managed by GC, and therefore can be easily used to make a memory leak. This is provided by DirectByteBuffer (http://download.oracle.com/javase/1.5.0/docs/api/java/nio/ByteBuffer.html#allocateDirect(int)).

  • If you can't use any of those, you still can make a memory leak by tricking the GC. The JVM is implemented using a generational garbage collection. What this means is that the heap is divided into areas: young, adults and elders. An object when its created starts at the young area. As it is used more and more, it progresses into adults up to elders. An object that reaches the eldery area most likely will not be garbage collected. You cannot be sure that an object is leaked and if you ask for a stop and clean GC it may clean it, but for a long period of time it will be leaked. More information is at (http://java.sun.com/docs/hotspot/gc1.4.2/faq.html)

  • Also, class objects are not required to be GC'ed. There might be a way to do it.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
  • 2
    The native memory allocated by a DirectByteBuffer is freed in a finalizer when the DirectByteBuffer is garbage collected. It certainly doesn't leak. – Boann Aug 31 '13 at 05:04
7

If the maximum heap size is X. Y1....Yn no of instances

So, total memory = number of instances X bytes per instance. If X1......Xn is bytes per instances, then total memory(M)=Y1 * X1+.....+Yn *Xn. So, if M>X, it exceeds the heap space.

The following can be the problems in code

  1. Use of more instances variable then local one.
  2. Creating instances every time instead of pooling object.
  3. Not creating the object on demand.
  4. Making the object reference null after the completion of operation. Again, recreating when it is demanded in program.
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
abishkar bhattarai
  • 6,848
  • 7
  • 41
  • 60
7

Throw an unhandled exception from the finalize method.

Basanth Roy
  • 5,536
  • 4
  • 22
  • 24
7

There are many answers on how to create a memory leak in Java, but please note the point asked during the interview.

"how to create a memory leak with Java?" is an open-ended question, whose purpose is to evaluate the degree of experience a developer has.

If I ask you "Do you have experience troubleshooting memory leaks in Java?", your answer would be a simple "Yes". I would have then to follow up with "Could you give me examples where you hat to troubleshoot memory leaks?", to which you would give me one or two examples.

However, when the interviewer asks "how to create a memory leak with Java?" the expected answer should follow alongs these lines:

  • I've encountered a memory leak ... (say when) [that shows me experience]
  • The code that was causing it was... (explain code) [you fixed it yourself]
  • The fix I applied was based on ... (explain fix) [this gives me a chance to ask specifics about the fix]
  • The test I did was ... [gives me the chance of asking other testing methodologies]
  • I documented it this way ... [extra points. Good if you documented it]
  • So, it is reasonable to think that, if we follow this in reverse order, which is, get the code I fixed, and remove my fix, that we would have a memory leak.

When the developer fails to follow this line of thought I try to guide him/her asking "Could you give me an example of how could Java leak memory?", followed by "Did you ever have to fix any memory leak in Java?"

Note that I am not asking for an example on how to leak memory in Java. That would be silly. Who would be interested in a developer who can effectively write code that leaks memory?

Alexandre Santos
  • 7,654
  • 7
  • 35
  • 60
  • Regarding the last sentence, the best way to win over the evil is knowing it well. If you want to write a secure web application, you should make yourself familiar with the most common exploit techniques and vulnerabilities, like SQL injections or buffer overflows. Similarly, if you want to write leak-free code, you should at least be able to describe the most common ways of leaking memory, like lost pointers in C/C++. Definitely less straightforward in Java, though. – Stefano Sanfilippo Jun 21 '15 at 16:40
7

The String.substring method in Java 1.6 create a memory leak. This blog post explains it:

How SubString method works in Java - Memory Leak Fixed in JDK 1.7

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Viraj
  • 4,175
  • 4
  • 27
  • 58
7

Most of the memory leaks I've seen in Java concern processes getting out of sync.

Process A talks to B via TCP, and tells process B to create something. B issues the resource an ID, say 432423, which A stores in an object and uses while talking to B. At some point the object in A is reclaimed by garbage collection (maybe due to a bug), but A never tells B that (maybe another bug).

Now A doesn't have the ID of the object it's created in B's RAM any more, and B doesn't know that A has no more reference to the object. In effect, the object is leaked.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
arnt
  • 7,178
  • 5
  • 20
  • 31
7

A few suggestions:

  • use commons-logging in a servlet container (a bit provocative perhaps)
  • start a thread in a servlet container and don't return from its run method
  • load animated GIF images in a servlet container (this will start an animation thread)

The above effects could be 'improved' by redeploying the application ;)

I recently stumbled upon this:

  • Calling "new java.util.zip.Inflater();" without calling "Inflater.end()" ever

Read http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5072161 and linked issues for an in-depth-discussion.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Peter
  • 1,104
  • 10
  • 10
  • To add to the discussion about what a memory leak is in my opinion the idea of "intentional" is important. Of course a field (static or not) pointing to a huge data structure is not yet a memory leak. But if the datastructure pointed to is of no use for your logic, just lingering around, polluting your heap, perhaps ever growing until GC gives up with an OOME, then i call it a "memory leak". The memory leaked is just no longer available to me. Just like in former times where i called malloc without ever returning this to os - purify to the rescue. – Peter Jul 22 '11 at 15:05
  • The inflater is a good one, while not true leak (if will be finalized) it eats up native memory very well and it's hard to diagnose. You deserve a vote (but I do not vote myself). I added some more info in my answer (didn't spot yours earlier) – bestsss Dec 27 '11 at 01:17
  • Finlizers were a bad idea, and there is no guarantee that they will ever be called. Google for Cliff Click and his comments about this... – Peter Feb 02 '12 at 11:39
  • All JVMs (minus JDK7 before 7.0.2) invoke finalizer(s) more or less in good fashion. Finalizer are absolutely necessary for Direct buffers to work (even more mapped files, esp. on Windows). They are just unreliable (baring that I know what Cliff Click says about) – bestsss Feb 02 '12 at 15:04
6

A memory leak in Java is not your typical C/C++ memory leak.

To understand how the JVM works, read the Understanding Memory Management.

Basically, the important part is:

The Mark and Sweep Model

The JRockit JVM uses the mark and sweep garbage collection model for performing garbage collections of the whole heap. A mark and sweep garbage collection consists of two phases, the mark phase and the sweep phase.

During the mark phase all objects that are reachable from Java threads, native handles and other root sources are marked as alive, as well as the objects that are reachable from these objects and so forth. This process identifies and marks all objects that are still used, and the rest can be considered garbage.

During the sweep phase the heap is traversed to find the gaps between the live objects. These gaps are recorded in a free list and are made available for new object allocation.

The JRockit JVM uses two improved versions of the mark and sweep model. One is mostly concurrent mark and sweep and the other is parallel mark and sweep. You can also mix the two strategies, running for example mostly concurrent mark and parallel sweep.

So, to create a memory leak in Java; the easiest way to do that is to create a database connection, do some work, and simply not Close() it; then generate a new database connection while staying in scope. This isn't hard to do in a loop for example. If you have a worker that pulls from a queue and pushes to a database you can easily create a memory leak by forgetting to Close() connections or opening them when not necessary, and so forth.

Eventually, you'll consume the heap that has been allocated to the JVM by forgetting to Close() the connection. This will result in the JVM garbage collecting like crazy; eventually resulting in java.lang.OutOfMemoryError: Java heap space errors. It should be noted that the error may not mean there is a memory leak; it could just mean you don't have enough memory; databases like Cassandra and Elasticsearch for example can throw that error because they don't have enough heap space.

It's worth noting that this is true for all GC languages. Below, are some examples I've seen working as an SRE:

  • Node.js using Redis as a queue; the development team created new connections every 12 hours and forgot to close the old ones. Eventually node was OOMd because it consumed all the memory.
  • Go (I'm guilty of this one); parsing large JSON files with json.Unmarshal and then passing the results by reference and keeping them open. Eventually, this resulted in the entire heap being consumed by accidental references I kept open to decode JSON.
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
6

One possibility is to create a wrapper for an ArrayList that only provides one method: one that adds things to the ArrayList. Make the ArrayList itself private. Now, construct one of these wrapper objects in global scope (as a static object in a class) and qualify it with the final keyword (e.g. public static final ArrayListWrapper wrapperClass = new ArrayListWrapper()). So now the reference cannot be altered. That is, wrapperClass = null won't work and can't be used to free the memory. But there's also no way to do anything with wrapperClass other than add objects to it. Therefore, any objects you do add to wrapperClass are impossible to recycle.

Gravity
  • 2,598
  • 1
  • 17
  • 28
5

In Java a "memory leak" is primarily just you using too much memory which is different than in C where you are no longer using the memory but forget to return (free) it. When an interviewer asks about Java memory leaks they are asking about JVM memory usage just appearing to keep going up and they determined that restarting the JVM on a regular basis is the best fix (unless the interviewer is extremely technically savvy).

So answer this question as if they asked what makes JVM memory usage grow over time. Good answers would be storing too much data in a HttpSessions with overly long timeout or a poorly implemented in-memory cache (singleton) that never flushes old entries. Another potential answer is having lots of JSPs or dynamically generated classes. Classes are loaded into an area of memory called PermGen that is usually small and most JVMs don't implement class unloading.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Chase
  • 2,933
  • 1
  • 26
  • 33
5

Swing has it very easy with dialogs. Create a JDialog, show it, the user closes it, and leak!

You have to call dispose() or configure setDefaultCloseOperation(DISPOSE_ON_CLOSE).

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
jorgeu
  • 669
  • 6
  • 14
4

If you don't use a compacting garbage collector, you can have some sort of a memory leak due to heap fragmentation.

user1050755
  • 9,463
  • 3
  • 35
  • 51
4

Lapsed Listerners is a good example of memory leaks: Object is added as a Listener. All references to the object are nulled when the object is not needed anymore. However, forgetting to remove the object from the Listener list keeps the object alive and even responding to events, thereby wasting both memory and CPU. See http://www.drdobbs.com/jvm/java-qa/184404011

Tarik
  • 9,314
  • 1
  • 19
  • 35
4

Carelessly using a non-static inner class inside a class which has its own life cycle.

In Java, non-static inner and anonymous classes hold an implicit reference to their outer class. Static inner classes, on the other hand, do not.

Here is a common example to have memory leak in Android, which is not obvious though:

public class SampleActivity extends Activity {

  private final Handler mLeakyHandler = new Handler() { // Non-static inner class, holds the reference to the SampleActivity outer class
    @Override
    public void handleMessage(Message msg) {
      // ...
    }
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Post a message and delay its execution for a long time.
    mLeakyHandler.postDelayed(new Runnable() {//here, the anonymous inner class holds the reference to the SampleActivity class too
      @Override
      public void run() {
     //....
      }
    }, SOME_TOME_TIME);

    // Go back to the previous Activity.
    finish();
  }}

This will prevent the activity context from being garbage collected.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
JaskeyLam
  • 13,279
  • 17
  • 103
  • 134
  • Would making `mLeakyHandler` static prevent it from leaking memory? And are there any (other) ways to prevent `mLeakyHandler` from leaking the activity? Also, how would you go about solving the same problem for the anonymous `Runnable` inner class? – ban-geoengineering Jun 24 '15 at 13:08
  • 1
    @ban-geoengineering Yes, make it static and if you need to involve the outter activity, make the handler to hold a WeakReference to the activity, please check http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html – JaskeyLam Jun 25 '15 at 02:20
2

import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class Main {
    public static void main(String args[]) {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            ((Unsafe) f.get(null)).allocateMemory(2000000000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Sapphire_Brick
  • 1,159
  • 7
  • 22
2

There are many good examples of memory leaks in Java, and I will mention two of them in this answer.

Example 1:

Here is a good example of a memory leak from the book Effective Java, Third Edition (item 7: Eliminate obsolete object references):

// Can you spot the "memory leak"?
public class Stack {
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    private Object[] elements;
    private int size = 0;

    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0) throw new EmptyStackException();
        return elements[--size];
    }

    /*** Ensure space for at least one more element, roughly* doubling the capacity each time the array needs to grow.*/
    private void ensureCapacity() {
        if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1);
    }
}

This is the paragraph of the book that describes why this implementation will cause a memory leak:

If a stack grows and then shrinks, the objects that were popped off the stack will not be garbage collected, even if the program using the stack has no more references to them. This is because the stack maintains obsolete references to these objects. An obsolete reference is simply a reference that will never be dereferenced again. In this case, any references outside of the “active portion” of the element array are obsolete. The active portion consists of the elements whose index is less than size

Here is the solution of the book to tackle this memory leak:

The fix for this sort of problem is simple: null out references once they become obsolete. In the case of our Stack class, the reference to an item becomes obsolete as soon as it’s popped off the stack. The corrected version of the pop method looks like this:

public Object pop() {
    if (size == 0) throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null; // Eliminate obsolete reference
    return result;
}

But how can we prevent a memory leak from happening? This is a good caveat from the book:

Generally speaking, whenever a class manages its own memory, the programmer should be alert for memory leaks. Whenever an element is freed, any object references contained in the element should be nulled out.

Example 2:

The observer pattern also can cause a memory leak. You can read about this pattern in the following link: Observer pattern.

This is one implementation of the Observer pattern:

class EventSource {
    public interface Observer {
        void update(String event);
    }

    private final List<Observer> observers = new ArrayList<>();

    private void notifyObservers(String event) {
        observers.forEach(observer -> observer.update(event)); //alternative lambda expression: observers.forEach(Observer::update);
    }

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void scanSystemIn() {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            notifyObservers(line);
        }
    }
}

In this implementation, EventSource, which is Observable in the Observer design pattern, can hold link to Obeserver objects, but this link is never removed from the observers field in EventSource. So they will never be collected by the garbage collector. One solution to tackle this problem is providing another method to the client for removing the aforementioned observers from the observers field when they don't need those observers any more:

public void removeObserver(Observer observer) {
    observers.remove(observer);
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Tashkhisi
  • 1,618
  • 3
  • 14
1

a memory leak is a type of resource leak that occurs when a computer program incorrectly manages memory allocations in such a way that memory which is no longer needed is not released => Wikipedia definition

It's kind of relatively context-based topic, you can just create one based on your taste as long as the unused references will never be used by clients, but still stay alive.

The first example should be a custom stack without nulling the obsolete references in Effective Java, item 6.

Of course there are many more as long as you want, but if we just take look at the Java built-in classes, it could be some as

subList()

Let's check some super silly code to produce the leak.

public class MemoryLeak {
    private static final int HUGE_SIZE = 10_000;

    public static void main(String... args) {
        letsLeakNow();
    }

    private static void letsLeakNow() {
        Map<Integer, Object> leakMap = new HashMap<>();
        for (int i = 0; i < HUGE_SIZE; ++i) {
            leakMap.put(i * 2, getListWithRandomNumber());
        }
    }



    private static List<Integer> getListWithRandomNumber() {
        List<Integer> originalHugeIntList = new ArrayList<>();
        for (int i = 0; i < HUGE_SIZE; ++i) {
            originalHugeIntList.add(new Random().nextInt());
        }
        return originalHugeIntList.subList(0, 1);
    }
}

Actually there is another trick we can cause memory leak using HashMap by taking advantage of its looking process. There are actually two types:

  • hashCode() is always the same but equals() are different;
  • use random hashCode() and equals() always true;

Why?

hashCode() -> bucket => equals() to locate the pair


I was about to mention substring() first and then subList() but it seems this issue is already fixed as its source presents in JDK 8.

public String substring(int beginIndex, int endIndex) {
    if (beginIndex < 0) {
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    if (endIndex > value.length) {
        throw new StringIndexOutOfBoundsException(endIndex);
    }
    int subLen = endIndex - beginIndex;
    if (subLen < 0) {
        throw new StringIndexOutOfBoundsException(subLen);
    }
    return ((beginIndex == 0) && (endIndex == value.length)) ? this
            : new String(value, beginIndex, subLen);
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Hearen
  • 6,019
  • 2
  • 36
  • 50
0

A real-time example of a memory leak before JDK 1.7:

Suppose you read a file of 1000 lines of text and keep them in String objects:

String fileText = 1000 characters from file

fileText = fileText.subString(900, fileText.length());

In above code I initially read 1000 characters and then did substring to get only the 100 last characters. Now fileText should only refer to 100 characters and all other characters should get garbage collected as I lost the reference, but before JDK 1.7 the substring function indirectly referred to the original string of last 100 characters and prevents the whole string from garbage collection and the whole 1000 characters will be there in memory until you lose reference of the substring.

You can create memory leak example like the above.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
  • I don,t think so. A new String is created and returned. Here is a code snippet from open-jdk 6 for subString function return ((beginIndex == 0) && (endIndex == count)) ? this : new String(offset + beginIndex, endIndex - beginIndex, value); – Karan Khanna Apr 19 '18 at 09:12
  • 1
    correct new string object is getting created but if you see it is passing value which is char array of original string and newly created string keeps the reference of complete char array. you can just compare the implementation from java 6 to 8, java 7 and 8 uses Arrays.copyOfRange(value, offset, offset+count) to return actual substring – Praveen Kumar Apr 19 '18 at 09:27
  • Got it. Thanks. – Karan Khanna Apr 19 '18 at 09:38
  • What do you mean by "real-time"? – Peter Mortensen May 12 '21 at 22:06
0

One of the Java memory leakings examples is MySQLs memory leaking bug resulting when ResultSets close method is forgotten to be called. For example:

while(true) {
    ResultSet rs = database.select(query);
    ...
    // going to next step of loop and leaving resultset without calling rs.close();
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Amir Fo
  • 3,044
  • 1
  • 25
  • 36
0

Create a JNI function containing just a while-true loop and call it with a large object from another thread. The GC doesn't like JNI very much and is going to keep the object in memory forever.

Jessie Lesbian
  • 653
  • 6
  • 14
-2

One of the easiest ways to implement a memory leak sample is to use a static method.

For example,

static List<int> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
    list.add(i);
}

system.sleep();

In this case, the JVM can't release the memory of list, cuz it's a static class and it always remains memory on heap.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Jimmy lau
  • 37
  • 1
  • 7
-4

From the Effective Java book (by Joshua Bloch):

  1. Whenever a class manages its own memory, the programmer should be alert for memory leaks

    public class Stack {
    
        private Object[] elements;
        private int size = 0;
        private static final int DEFAULT_INITIAL_CAPACITY = 16;
    
        public Stack() {
            elements = new Object[DEFAULT_INITIAL_CAPACITY];
        }
    
        public void push(Object e) {
            ensureCapacity();
            elements[size++] = e;
        }
    
        public Object pop() {
            if (size == 0)
                throw new EmptyStackException();
            return elements[--size];
        }
    
        /**
         * Ensure space for at least one more element, roughly doubling the capacity
         * each time the array needs to grow.
         */
        private void ensureCapacity() {
            if (elements.length == size)
                elements = Arrays.copyOf(elements, 2 * size + 1);
        }
    }
    

Can you spot the memory leak? So where is the memory leak? If a stack grows and then shrinks, the objects that were popped off the stack will not be garbage collected, even if the program using the stack has no more references to them.

This is because the stack maintains obsolete references to these objects. An obsolete reference is simply a reference that will never be dereferenced again. In this case, any references outside of the “active portion” of the element array are obsolete. The active portion consists of the elements whose index is less than size.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
gurubelli
  • 1,049
  • 1
  • 7
  • 12
  • Why was this downvoted? It is actually taken from a book. – kiltek Aug 02 '18 at 07:19
  • I think it is downvoted because this example will not create obsolete references. As long as this stack is alive, each reference is accessible through the elements array. Even if `size` changes every time `pop` is called, it is still possible to iterate over the complete array using its `length` property. Therefore there are no obsolete references. I must say that it is usual that a collection releases ownership in a function such as `pop` though, but this example will not create a memory leak which is the original question – 0xDEADC0DE Dec 27 '18 at 13:52
-5

Here is a very simple Java program that will run out of space

public class OutOfMemory {

    public static void main(String[] arg) {

        List<Long> mem = new LinkedList<Long>();
        while (true) {
            mem.add(new Long(Long.MAX_VALUE));
        }
    }
}
rds
  • 24,304
  • 16
  • 97
  • 124
stones333
  • 7,618
  • 1
  • 22
  • 24
  • 35
    -1 this runs out of memory for sure, because the requirement is to have an infinite amount of memory. I don't call this a memory leak. It is just a stupid program. – rds Jan 17 '13 at 10:59
  • 3
    also -1, not a mem leak, thats just allocating too much – kritzikratzi Apr 01 '13 at 20:04
-5

There's no such thing as a memory leak in Java. Memory leak is a phrase borrowed from C et al. Java deals with memory allocation internally with the help of the GC. There's memory wastefulness (ie. leaving stranded objects), but not memory leak.

-7

Just like this!

public static void main(String[] args) {
    List<Object> objects = new ArrayList<>();
    while(true) {
        objects.add(new Object());
    }
}
akhambir
  • 65
  • 10
  • 9
    This is not an example of memory leak. You are just trying to consume the whole memory here with your list. Memory leak is when obsolete references cannot be garbage collected. – Karan Khanna Apr 19 '18 at 08:55