JDK-4363937 : ObjectOutputStream is creating a memory leak
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io:serialization
  • Affected Version: 1.3.0,1.3.1
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: linux,windows_2000
  • CPU: x86
  • Submitted: 2000-08-18
  • Updated: 2001-01-10
  • Resolved: 2001-01-10
Related Reports
Duplicate :  
Relates :  
Description

Name: skT45625			Date: 08/18/2000


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

When using a loop to serialize objects to a file, the ObjectOutputStream object
never seems to release the references to objects that have already been written
to the file.  Since the garbage collector can't clean up these objects, it's
relatively simple to generate an OutOfMemoryError.

Here is some sample code:

public class MyObject() {
    static public void main(String[] args) {
        try {
            File file = File.createTempFile("test", null);
            FileOutputStream testFile = new FileOutputStream
(file.getAbsolutePath(), true);
            ObjectOutputStream testOut = new ObjectOutputStream(testFile);

            // Write a bunch of double arrays to the file
            for (int i = 0; i < 100; i++) {
                testOut.writeObject(new double[1000000]);
                testOut.flush();
            }

            testOut.close();
            testFile.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Before the program finishes, an OutOfMemoryError is generated (using the
default memory allocation for the virtual machine).  Shouldn't each double
array be marked for garbage collection once it has been written to the stream?
If so, is this an io error or a garbage collection error?
(Review ID: 108636) 
======================================================================

Name: krC82822			Date: 10/13/2000


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0)
Java HotSpot(TM) Client VM (build 1.3.0, mixed mode)


import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.File;
import java.io.FileOutputStream;

public class MemoryTest
{
	public static void main(String[] args)
	{
		try
		{
			File file = new File("/dev/null");
			long quantity = Long.parseLong(args[0]);

			ObjectOutputStream out
			          = new ObjectOutputStream(new FileOutputStream(file));

			for(long i = 0; i < quantity; i++)
			{
				out.writeObject(new Long(i));

				// eval1127:  even a flush() here after every 200 objects did not help
				
				if ((i % 50000) == 0)
				{
					System.out.println(""+i);
				}
			}
		}
		catch(Exception e)
		{
			System.out.println(e.toString());
		}
	}
}

The above code produces an OutOfMemoryError when the iteration count is high
enough.

Suggest you run as:

java -Xmx10M -Xms10M  MemoryTest 10000000

This produces the following output:

0
50000
100000
150000
200000
250000
Exception in thread "main" java.lang.OutOfMemoryError
        <<no stack trace available>>

This has been tested on Linux, Solaris and Windows NT.  All were using JDK1.3.
All produced the same output.

I'm assuming the error is something to do with Serialization as the error does
not seem to occur when the writeObject line is removed.
(Review ID: 110753)
======================================================================

Comments
WORK AROUND Name: skT45625 Date: 08/18/2000 None. ====================================================================== Call ObjectOutputStream.reset(). See evaluation for details. michael.warres@east 2001-01-10
10-01-2001

EVALUATION This is not a bug; it is simply how serialization works. As noted in the comments for this bug, ObjectOutputStream must maintain a table of written objects in order to determine when to write back-references to objects already serialized in the stream. The comments also note that ObjectOutputStream's handle table could use weak references instead to avoid unnecessarily pinning objects. While attractive, this would slow performance; moreover, the serialization protocol does not include any means for a sender to indicate to a receiver that a given object has been reclaimed on the sending side and hence should be released in the receiver's handle table as well. Thus, a memory leak would still exist on the receiving side, and using weak references on the sending side would encourage programming practices (i.e., not calling ObjectOutputStream.reset()) which would exacerbate the receiver's memory leak. The proper way to prevent memory leaks when serializing large numbers of objects is to periodically reset() the ObjectOutputStream. In addition to clearing the sender's handle table, this sends a reset code to the receiver, indicating that the receiving ObjectInputStream should also clear its handle table, in the process unpinning objects on both sides of the communication. michael.warres@east 2001-01-10
10-01-2001