使用 ImageMagick 调整 JPG 大小时(不增加内存)如何防止 OOM?

How can I prevent OOMs when resizing JPGs with ImageMagick (without increasing memory)?

使用 ImageMagick 调整 JPG 大小时似乎忽略了 -limit 选项。

以下命令使用docker在可用内存有限(100MB)的机器上模拟运行ImageMagick:ImageMagick命令传递一个4958 × 6198 JPEG(原始文件大小:5.5MB) ) 调整大小,使用 -limit memory 5MiB.

结果是 ImageMagick 被容器的 OOM Killer 杀死,这意味着 ImageMagick 试图分配超过 ~100MB,而不是保持在它被指示的 ~5MB 限制内。 如果在 docker run 上增加(或删除)--memory 100m 标志,命令将成功:

# Download a 5.5MB JPEG (4958 × 6198)
curl 'https://images.unsplash.com/photo-1534970028765-38ce47ef7d8d?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&dl=trail-5yOnGsKUNGw-unsplash.jpg' \
     -o 5500kb-image.jpg

docker run --memory 100m \
           -v $(pwd):/imgs \
           dpokidov/imagemagick \
           /imgs/5500kb-image.jpg \
           -debug All -limit memory 5MiB -limit map 10MiB -resize 400 \
           /imgs/5500kb-image-resized.jpg

我如何在调整 JPEG 大小时使用内存绑定 ImageMagick?

一张4958×6198的图片有30,729,684个像素。每个都有一个 R、G 和 B 通道,可生成 92,189,052 个样本。由于每个样本通常以 16 位(2 字节)分辨率存储,因此您需要 180+MB 的 RAM 来保存它……以及 space 用于输出图像。

如果这是您最关心的问题,您通常会发现 libvips 更节省内存。示例 显示了相对内存要求以及如何衡量它们。

我认为你的参数顺序错误。

如果您使用 linux,/usr/bin/time 非常便于测量峰值内存使用。你是运行这个命令:

$ /usr/bin/time -f %M:%e \
    convert \
        5500kb-image.jpg \
        -limit memory 5MiB -limit map 10MiB \
        -resize 400 5500kb-image-resized.jpg
346060:2.37

即。 350mb 内存和 2.37s CPU 时间。

如果你把限制放在第一位,你会看到:

$ /usr/bin/time -f %M:%e \
    convert \
        -limit memory 5MiB -limit map 10MiB \
        5500kb-image.jpg -resize 400 5500kb-image-resized.jpg
105468:2.64

现在只有 105mb 的峰值,并且运行时间大致相同。您需要在加载图像之前设置限制。

正如 Mark 所说,vipsthumbnail 速度更快,内存消耗更少。我看到了:

$ /usr/bin/time -f %M:%e \
    vipsthumbnail 5500kb-image.jpg --size 400 -o 5500kb-image-resized.jpg
133676:0.28

130mb 和 0.28s。

这还是比较高的。您的图像是渐进式 JPG --- 在开始缩略图之前,必须将它们完全加载到内存中,并且不可能利用 jpeg 加载时收缩之类的东西。

如果我将您的图片转换为普通的 jpeg,我会看到:

$ /usr/bin/time -f %M:%e \
    vipsthumbnail 5500kb-image-regular.jpg --size 400 -o 5500kb-image-resized.jpg
40200:0.09

40mb 和 CPU.

的 0.1s

vipsthumbnail 可以调整非常大的图像,只需要少量内存,例如:

$ vipsheader st-francis.jpg 
st-francis.jpg: 30000x26319 uchar, 3 bands, srgb, jpegload
$ /usr/bin/time -f %M:%e \
    vipsthumbnail st-francis.jpg --size 400 -o 5500kb-image-resized.jpg
49692:2.52

50mb 和 2.5s。