views:

126

answers:

2

I'm trying to determine how much heap any given TYPE_INT_ARGB BufferedImage will use so that, for a program which is doing some image processing, I can set a reasonable max heap based on the size of image we feed it.

I wrote the following program as a test, which I then used to determine the least maximum heap under which it would run without an OutOfMemoryError:

import java.awt.image.BufferedImage;

public class Test {
  public static void main(String[] args) {
    final int w = Integer.parseInt(args[0]);
    final int h = Integer.parseInt(args[1]);

    final BufferedImage img =
      new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

    System.out.println((4*w*h) >> 20);
  }
}

(The printed value is the expected size of the int[] in which the BufferedImage's pixel data is stored.) What I expected to find was that the required max heap is something like x + c, where x is the size of the data array and c is a constant consisting of the sizes of the classes which are loaded, the BufferedImage object, etc. This is what I found instead (all values are in MB):

4*w*h   min max heap
-----   ------------
  5          -
 10         15
 20         31
 40         61
 80        121
160        241

1.5x is a good fit for the observations. (Note that I found no minimum for the 5MB image.) I don't understand what I'm seeing. What are these extra bytes?

A: 

A BufferedImage contains both a Raster, with its associated DataBuffer, as well as a ColorModel whose contents may also depend on the image's dimensions.

trashgod
Last I checked, `Raster` and `DataBuffer` were just containers providing an interface for accessing the data---the `WritableRaster` has no members, while `Raster` has a half-dozen `int`s and a reference to a `DataBuffer` and a `SampleModel`. Same deal with `DataBuffer` (or, in this case, `DataBufferInt`). `ColorModel` doesn't depend on the image data at all, so its size shouldn't depend on the size of the image.
uckelman
@uckelman: You're right about the `ColorModel`; the bulk of the data is in the private `data` and `dataBuffer` inherited by `Raster`.
trashgod
+2  A: 

There seem to be a bug in Oracle's VM introduced somewhere between 1.6.0_16 and 1.6.0_20. You can even reduce the problem to allocating an int array, as the problem is not only related to BufferedImage.

With 1.6.0_16, I need at least 413 MB heap to allocate an int array with 100,000,000 elements, which seem reasonable. With 1.6.0_20, the same operation requires at least 573 MB heap space, although only appr 400,000,000 bytes are actually used after allocating the array.

jarnbjo
I tested on 1.6.0_18. I wonder if this is a bug Oracle knows about? if it afflicts arrays of all sorts, or just `int[]`?
uckelman
The difference is rather big, but not huge. Maybe they added some extra internal book-keeping to arrays or something. Should not be too hard to find out, the source is still free right?
Amigable Clark Kant
I tried this for `byte[]`, and it seems to affect those as well... I haven't been able to find anything in Oracle's bug tracker about this.
uckelman
If anybody finds a reference to this problem elsewhere, I'd love to know about it.
uckelman