Reputation: 26870
I just had an interview where I was asked to create a memory leak with Java.
Needless to say, I felt pretty dumb, having no idea how to start creating one.
What would an example be?
Upvotes: 3752
Views: 760816
Reputation: 50041
I experienced a very real memory leak with javax.swing.JPopupMenu
.
I have a GUI application which displays multiple tabbed documents. After closing a document, it lingered in memory if any right-click context menu had been used anywhere on the tab. My menus are shared among tabs, and it turns out that after you call popupMenu.show(Component invoker, int x, int y)
, that component quietly persists as the menu's "invoker" even after the menu is closed, until it is next changed, or cleared by setInvoker(null)
. This is NOT clearly documented! Indirectly, the invoker reference was persisting the entire document and every object associated with it.
Each context menu can only keep one reference to an old component this way, so this memory leak cannot grow without bound.
Upvotes: 1
Reputation: 405995
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.
Upvotes: 75
Reputation: 6050
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 instances of this class directly, but you may use reflection to get an instance.
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();
}
}
}
Upvotes: 59
Reputation: 11087
Static field holding an object reference [especially a final field]
class MemorableClass {
static final ArrayList list = new ArrayList(100);
}
(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.
Upvotes: 1366
Reputation: 76719
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 implementing the finalize
method.
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 the JVM will reclaim memory due to unreachable objects being collected, resources (including memory) associated with the Connection
object might not be reclaimed.
As such, Connection's final method does not clean up everything. One might 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 implemented finalize
, the compiler can throw exceptions during finalization. The resulting behavior is that any memory associated with the now "dormant" object will not be reclaimed by the compiler, as finalize
is guaranteed to be invoked only once.
The above scenario of encountering exceptions during object finalization is related to another scenario that could 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
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), orSockets
or Files,
but not closing them when they are no longer needed (similar to the above example involving the Connection
class).Upvotes: 151
Reputation: 707
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 anymore). 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.
Upvotes: 31
Reputation: 15
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 the 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 the 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 a memory leak example like the above.
Upvotes: 1
Reputation: 2262
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 links to Observer
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 anymore:
public void removeObserver(Observer observer) {
observers.remove(observer);
}
Upvotes: 16
Reputation: 1565
It's pretty easy:
Object[] o = new Object[]{};
while(true) {
o = new Object[]{o};
}
Upvotes: 0
Reputation: 139
You can try making many buffered readers try to open the same file at once with a while
loop with a condition that is never false. And the cherry on top is these are never closed.
Upvotes: -1
Reputation: 61
A little improvement to previous answers (to generate memory leak faster) is to use instances of DOM Document loaded from big XML files.
Upvotes: -2
Reputation: 5970
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();
}
Upvotes: 0
Reputation: 7838
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
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;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);
}
Upvotes: 3
Reputation: 2419
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.
Upvotes: 11
Reputation:
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:
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.Upvotes: 8
Reputation: 15765
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.
Upvotes: 5
Reputation: 5411
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
Upvotes: 7
Reputation: 21778
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.
Upvotes: 9
Reputation: 50041
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.
Upvotes: 14
Reputation: 7651
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
Upvotes: 7
Reputation: 689
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)
.
Upvotes: 5
Reputation: 3183
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.
Upvotes: 5
Reputation: 1312
A few suggestions:
The above effects could be 'improved' by redeploying the application ;)
I recently stumbled upon this:
Read https://bugs.java.com/bugdatabase/view_bug?bug_id=5072161 and linked issues for an in-depth-discussion.
Upvotes: 7
Reputation: 9685
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.
Upvotes: 8
Reputation: 21
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.
Upvotes: 8
Reputation: 15788
Everyone always forgets the native code route. Here's a simple formula for a leak:
malloc
. Don't call free
.Remember, memory allocations in native code come from the JVM heap.
Upvotes: 21
Reputation: 4295
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...
Upvotes: 15
Reputation: 1319
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 {
}
Upvotes: 10
Reputation: 668
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.
Upvotes: 12
Reputation: 12885
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.
Upvotes: 42