在ColdFusion 11中使用ImageReadBase64()读取大型图像时出现"java.lang.OutOfMemoryError: Java heap space"错误。

4
我有一个简单的REST API,使用ColdFusion 11构建,允许供应商更新产品信息。他们发送的大部分数据(约30个属性)都是简单的值——字符串和数字。一个属性是代表图像文件的Base64编码字符串。REST API会在数据库中更新简单的数据值,然后读取图像并调整大小为适用于网站使用的4种尺寸。我注意到有时供应商会在某些请求中发送大型图像(20MB+),这些请求经常导致“java.lang.OutOfMemoryError:Java堆空间”在调用ImageReadBase64()函数的行上发生。我们在该服务器上运行其他Web应用程序,似乎处理这些图像锁定的内存会导致这些应用程序出现问题。我正在尝试弄清楚是否可以在代码中采取任何措施来减少这些问题,即使只是找出一种方法来在图像“太大”(超过一定大小)时不处理它们。下面是处理图像的所有代码:
public struct function getDimensionsToEnlarge(
    required numeric imageWidth,
    required numeric imageHeight,
    required numeric minWidth,
    required numeric minHeight
    ) {
    LOCAL.Dimensions={
        width=-1,
        height=-1
        };

    if  (   ARGUMENTS.minHeight > 0
        &&  ARGUMENTS.minWidth > 0
        &&  ARGUMENTS.imageHeight < ARGUMENTS.minHeight
        &&  ARGUMENTS.imageWidth < ARGUMENTS.minWidth
        ) {
        LOCAL.Dimensions.width=ARGUMENTS.minWidth;
        LOCAL.Dimensions.height=ARGUMENTS.minHeight;
    }

    return LOCAL.Dimensions;
}

public struct function getDimensionsToShrink(
    required numeric imageWidth,
    required numeric imageHeight,
    required numeric maxWidth,
    required numeric maxHeight
    ) {
    LOCAL.Dimensions={
        width=-1,
        height=-1
        };

    if  (   ARGUMENTS.maxHeight > 0
        &&  ARGUMENTS.maxWidth > 0
        &&  (   ARGUMENTS.imageHeight > ARGUMENTS.maxHeight
            ||  ARGUMENTS.imageWidth > ARGUMENTS.maxWidth
            )
        ) {
        LOCAL.Dimensions.width=ARGUMENTS.maxWidth;
        LOCAL.Dimensions.height=ARGUMENTS.maxHeight;
    }

    return LOCAL.Dimensions;
}

public struct function getDimensionsToFit(
    required numeric imageWidth,
    required numeric imageHeight,
    required numeric minWidth,
    required numeric minHeight,
    required numeric maxWidth,
    required numeric maxHeight
    ) {
    LOCAL.Dimensions={
        width=-1,
        height=-1
        };

    LOCAL.Dimensions =
        getDimensionsToEnlarge(
            imageHeight=ARGUMENTS.imageHeight,
            imageWidth=ARGUMENTS.imageWidth,
            minWidth=ARGUMENTS.minWidth,
            minHeight=ARGUMENTS.minHeight
            );

    if (LOCAL.Dimensions.width < 0 && LOCAL.Dimensions.height < 0)
        LOCAL.Dimensions =
            getDimensionsToShrink(
                imageHeight=ARGUMENTS.imageHeight,
                imageWidth=ARGUMENTS.imageWidth,
                maxWidth=ARGUMENTS.maxWidth,
                maxHeight=ARGUMENTS.maxHeight
                );

    return LOCAL.Dimensions;
}

public any function scale(
    required any image,
    string action="fit",
    numeric minWidth=-1,
    numeric minHeight=-1,
    numeric maxWidth=-1,
    numeric maxHeight=-1
    ) {
    LOCAL.Dimensions={
            width=-1,
            height=-1
        };
    LOCAL.Image=Duplicate(ARGUMENTS.image);

    switch (ARGUMENTS.action) {
        case "shrink":
            LOCAL.Dimensions =
                getDimensionsToShrink(
                    imageHeight=LOCAL.Image.getHeight(),
                    imageWidth=LOCAL.Image.getWidth(),
                    maxWidth=ARGUMENTS.maxWidth,
                    maxHeight=ARGUMENTS.maxHeight
                );

            break;
        case "enlarge":
            LOCAL.Dimensions =
                getDimensionsToEnlarge(
                    imageHeight=LOCAL.Image.getHeight(),
                    imageWidth=LOCAL.Image.getWidth(),
                    minWidth=ARGUMENTS.minWidth,
                    minHeight=ARGUMENTS.minHeight
                );

            break;
        default:
            LOCAL.Dimensions =
                getDimensionsToFit(
                    imageHeight=LOCAL.Image.getHeight(),
                    imageWidth=LOCAL.Image.getWidth(),
                    minWidth=ARGUMENTS.minWidth,
                    minHeight=ARGUMENTS.minHeight,
                    maxWidth=ARGUMENTS.maxWidth,
                    maxHeight=ARGUMENTS.maxHeight
                );

            break;
    }

    if (LOCAL.Dimensions.width > 0 && LOCAL.Dimensions.height > 0) {
        ImageSetAntialiasing(LOCAL.Image, "on");

        ImageScaleToFit(
            LOCAL.Image,
            LOCAL.Dimensions.width,
            LOCAL.Dimensions.height
            );
    }

    return LOCAL.Image;
}

public void function createLargeThumbnail(required any image) {
    ImageWrite(
        scale(image=ARGUMENTS.image, maxHeight=500, maxWidth=700),
        getLargeImagePath(),
        0.75,
        true
        );

    return;
}

public void function createMediumThumbnail(required any image) {
    ImageWrite(
        scale(image=ARGUMENTS.image, maxHeight=300, maxWidth=300),
        getMediumImagePath(),
        0.75,
        true
        );

    return;
}

public void function createSmallThumbnail(required any image) {
    ImageWrite(
        scale(image=ARGUMENTS.image, maxHeight=50, maxWidth=50),
        getSmallImagePath(),
        0.75,
        true
        );

    return;
}

public void function createMobileThumbnail(required any image) {
    ImageWrite(
        scale(image=ARGUMENTS.image, maxHeight=50, maxWidth=300),
        getMobileImagePath(),
        0.75,
        true
        );

    return;
}

public void function createProductThumbnails(required any image) {
    createLargeThumbnail(argumentCollection=ARGUMENTS);
    createMediumThumbnail(argumentCollection=ARGUMENTS);
    createSmallThumbnail(argumentCollection=ARGUMENTS);
    createMobileThumbnail(argumentCollection=ARGUMENTS);

    return;
}

createProductThumbnails(ImageReadBase64(ARGUMENTS.ImageUpload));

有什么我需要做来启动垃圾回收吗?

感谢您的帮助!


1
你使用的是哪个操作系统?你考虑过使用CFExecute和类似GraphicsMagick的东西吗?我发现GM更快,更兼容各种图像格式和调色板...也没有内存不足的问题。 - James Moberg
1个回答

1
你在每个 createXXXThumbnail() 中调用了 scale() 四次,通过参数显式地 duplicate() 传递的图像对象,从而将内存使用量增加了四倍。你还四次调用本地的 ImageScaleToFit() 使用昂贵的默认插值方法,这可能会在内部创建另一个字节数组。看似无害的 20 MB 在处理过程中很容易膨胀到 160 MB 或更多。

明白了。不过有趣的是,我经常在第一次调用时看到这些错误:createProductThumbnails(ImageReadBase64(ARGUMENTS.ImageUpload)); 有什么减少影响的建议吗? - Eric Belair

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接