JDK-4827358 : Use of finalization in JPEGImageReader/Writer degrades performance
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.imageio
  • Affected Version: 1.4.1,1.4.2
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2003-03-05
  • Updated: 2003-09-15
  • Resolved: 2003-09-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other Other
1.4.2_18-revFixed 1.4.2_19Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Description

Name: nt126004			Date: 03/04/2003


FULL PRODUCT VERSION :
java version "1.4.1_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_02-b06)
Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode)

FULL OS VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Memory allocation doesn't wait for finalization to catch up.
Almost all programs run more than 1 thread which is creating objects, meanwhile only one thread is finalizing them, eventually OutOfMemoryErrors are thrown at almost random places throughout the code, making the code extremely fragile.

Changing VM paramters to alter Garbage Collector behaviour makes no difference, the code fails no matter what the parameters.  Increasing the max heap size only delays the problem.

This problem only started to be really bad when JDK 1.4 came out.  The cause of this is that many of the new imageio and nio classes have finalize methods causing them to require finalizing before they can get garbage collected.  Despite the fact the the Finalizer thread runs at a higher priority, these new classes still block for a short amount of time hence finalization is getting blocked.

The more threads allocating objects requiring finalization the worse the problem gets.

Some of the imageio classes are using several meg of memory, which could easily be garbage collected before finalization was run.  Simply have the image classes hold a sub object with a finalize method and a handle such that it can call dispose instead of the image classes directly having the finalize method and hence having to wait for the Finalizer thread before they release several megs of memory.  The problem still needs to get fixed, but this would atleast give programs using the imageio a chance to continue without the bug getting fixed.

Related Bugs: 4811982, 4640743, 4239841

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
run code and wait for the OutOfMemoryError

EXPECTED VERSUS ACTUAL BEHAVIOR :
With each of the 2 new threads only using 1 object each, I would expect this code to run forever without a problem.  The code only needs about 2MB to run, yet it throws OutOfMemoryErrors no matter how much memory the VM allocates to it.
Thread dies due to OutOfMemoryError.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
class TestObject {
  private byte[] bytes;
  private static int createdCount;
  private static int finalizedCount;

  public TestObject() {
    bytes = new byte[1000000];
    try {
      Thread.sleep(500);
    }
    catch (InterruptedException ex) {
    }
    System.out.println("Created " + ++createdCount);
  }

  public void finalize() {
    try {
      Thread.sleep(500);
    }
    catch (InterruptedException ex) {
    }
    System.out.println("Finalized " + ++finalizedCount);
  }
}

class TestThread extends Thread {
  public void run() {
    while (true) {
      TestObject testObject = new TestObject();
      // do something with object
      testObject = null; // allow it to get garbage collected
      // continue with something else
    }
  }
}

public class Test {
  public static void main(String[] args) {
    new TestThread().start();
    new TestThread().start();
  }
}
---------- END SOURCE ----------
(Review ID: 182033) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger FIXED IN: tiger INTEGRATED IN: tiger tiger-b20
14-06-2004

EVALUATION We can't build a garbage collector for Java that would "wait for finalization to catch up" before throwing an OutOfMemoryError since finalize() methods can themselves allocate memory, and we can't prevent that without making some fairly extreme changes to the language itself. The invocation of an object's finalize() method can be delayed an arbitrarily long time from the moment that the object is detected to be finalizable by the GC. Objects with finalize() methods also have longer lifetimes since they have to be kept around long enough for the GC to discover that they're finalizable, finalize them, and then finally reclaim them. Finalization is hence, at best, a back-stop mechanism for deallocating external resources such as I/O or image buffers. Owing to the performance overhead of finalization the NIO channel classes were revised so as not to use it in 1.4.2 (4777499). I'm forwarding this bug to the Image I/O team for further evaluation. -- ###@###.### 2003/3/6 We should remove the finalize() methods and instead make use of the Java 2D Disposer mechanism for disposing native resources. There are some explicit System.gc() calls in the JPEG ImageReader/Writer plugins (see bug 4867874) that can be removed once the Disposer is used. (These two bugs should be handled simultaneously...) ###@###.### 2003-05-23
23-05-2003