为什么 BufferedImages 在程序运行时会增加它们使用的 ram 数量?

Why do BufferedImages increase the amount of ram they use as the program runs?

在Java中,由于使用了BufferedImage,我遇到了OutOfMemoryError。当我向控制台打印出 BufferedImage 单独使用了多少内存(以字节为单位)时,我注意到他使用的字节数呈指数增长。我的结果是这样的:

    7396
    12996
    23104
    40804
    71824
    125316
    217156
    372100
    630436
    1060900
    1763584
    2903616
    4726276
    7595536
    12054784
    18887716
    29181604
    44435556
    66650896
    98446084
    143089444
    204547204
    -249500608
    -140383168

我使用以下代码生成结果:

    while (true) {
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        DataBuffer buff = img.getRaster().getDataBuffer();
        System.out.println(buff.getSize() * DataBuffer.getDataTypeSize(buff.getDataType()) / 8); 
    }

为什么这种增加如此之大,我怎样才能避免这种增加的发生?另外,数字前面有一个负号(最后2个)是什么意思?

编辑:

请注意宽度和高度不断变化,但我不希望它们增加(抱歉)

当您创建 TYPE_INT_ARGBBufferedImage(或任何 TYPE_INT_*,实际上)时,您正在创建一个 int 支持数组来保存您的像素,即恰好 width * height 长。由于 Java int 是 32 位或 4 字节,因此该数组将使用 width * height * 4 字节。您代码中的 DataBuffer 只是这个后备数组的薄包装。

因此,您看到的增长完全在意料之中。根据堆的大小,您会 运行 在某个时候内存不足,试图创建更大的 BufferedImages。

突然出现负值的原因,很简单,就是你的表达:

buff.getSize() * DataBuffer.getDataTypeSize(buff.getDataType()) / 8
buff.getSize() 足够大时,

将导致 integer overflow

作为Java语言中的*/运算符have equal precedence,表达式会从左到右求值,乘法会溢出,即使如果最终结果(除以 8)应该是有效的 int。您可以通过添加括号强制先进行除法来修复它:

buff.getSize() * (DataBuffer.getDataTypeSize(buff.getDataType()) / 8)

或者简单地使用 longs:

(long) buff.getSize() * (long) DataBuffer.getDataTypeSize(buff.getDataType()) / 8L