Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4363937
Votes 14
Synopsis ObjectOutputStream is creating a memory leak
Category java:serialization
Reported Against 1.3 , 1.3.1 , kest-linux-fcs
Release Fixed
State 11-Closed, Not a Defect, bug
Priority: 4-Low
Related Bugs 4504228 , 6525563
Submit Date 18-AUG-2000
Description




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  customer 
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) 
======================================================================




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)
======================================================================
Work Around




None.
======================================================================


Call ObjectOutputStream.reset().  See evaluation for details.

  xxxxx@xxxxx   2001-01-10
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.

  xxxxx@xxxxx   2001-01-10
Comments
  
  Include a link with my name & email   

Submitted On 16-NOV-2000
ToBe
ObjectOutputStream includes a &quot;feature&quot; that enables it to 
serialize objects that contain circular references. 
Unfortunately, this feature is implemented in such a way 
that ObjectOutputStream keeps strong references to all 
objects that are written. This will in time result in a 
OutOfMemoryError when a large enough amount of objects have 
been written using the same ObjectOutputStream object. The 
same will happen when reading a large enough amount of 
objects using ObjectInputStream.

The normal way to prevent this from happening is to call 
the ObjectOutputStream.reset() method regularly, to clear 
all strong references. However, in JDK1.3 a bug was 
introduced in that method (see bug id 4332184) that 
prevented the references from ever being cleared. So, the 
only way to make written objects eligible for garbage 
collection is to clear all references to the 
ObjectOutputStream object itself (again, see bug id 4332184 
for a more complete description of this workaround). Of 
course, yet another workaround is to use JDK1.2 instead of 
1.3...

I consider this a SERIOUS bug, and I sincerely hope that it 
will be fixed in a maintenance release in the near future 
and not in Merlin (JDK1.4) as stated in the evaluation of 
bug 4332184. But it didn't really put my mind at ease when 
the line &quot;Fix is not integrated properly in Merlin.&quot; popped 
up in the description of the bug a while ago. Ah, well. I 
guess I'll just keep on hoping...


Submitted On 16-NOV-2000
guvener
Exactly the same error occurs with 
ObjectInputStream.readObject()


Submitted On 05-DEC-2000
edlund
What's the workaround for ObjectInputStream.readObject()? 
The reset() method doesn't work here.


Submitted On 08-DEC-2000
ToBe
The method reset() is not actually implemented in 
ObjectInputStream, for quite good reasons i migth add. So 
the only way to reset an ObjectInputStream is to reset its 
associated ObjectOutputStream. By doing so a TC_RESET code 
will be written to the stream and when it is read by the 
ObjectInputStream a reset will be performed by calling the 
private method resetStream().


Submitted On 31-JAN-2001
csize
However it should be noted that the reset method for the ObjectOutputStream does not work correctly i.e. the  
wireHandle2Object array is not properly reinitialized (See Bug Report 4332184 which has been confirmed), so 
while calling reset is the correct method to prevent leaks the method NEEDS to work properly. 



PLEASE NOTE: JDK6 is formerly known as Project Mustang