Skip to content
MagickCmd报错 › cache resources exhausted / 宽高超出限制

cache resources exhausted / 宽高超出限制

ImageMagick 的资源限制写在 policy.xml 里。如何查看当前限制、怎么安全地放宽,以及为什么真正的原因通常是 PDF 的 density 设得太大。

convert: cache resources exhausted 'input.jpg' @ error/cache.c/OpenPixelCache/4083
convert: width or height exceeds limit 'input.png' @ error/cache.c/OpenPixelCache/3742

发生了什么

ImageMagick 对内存、磁盘、面积和像素尺寸都设了上限,防止恶意构造的图片把主机资源吃干。和 PDF 那条封锁一样,这些限制也在 policy.xml 里,而且在一系列拒绝服务报告之后被收得相当紧。

查看当前限制

magick -list resource
Resource limits:
  Width: 16KP        Height: 16KP       Area: 128MP
  Memory: 256MiB     Map: 512MiB        Disk: 1GiB
  Thread: 8          Time: unlimited

16KP 表示 16000 像素。任何一项超标都会失败。

放宽之前,先检查你的 density

最常见的触发原因并不是一张巨大的照片,而是转 PDF 时 density 和页面尺寸不匹配:

magick -density 600 poster.pdf out.png

A0 海报按 600 DPI 渲染大约是 8 万像素宽,接近 200 亿像素。这不是该去放宽的限制,是 density 本身就写错了。屏幕用途 150 完全够。density 怎么选见 PDF 那一页

放宽限制

编辑 policy.xml(用 magick -list policy 找到它)里 domain="resource" 那几行:

<policy domain="resource" name="memory" value="4GiB"/>
<policy domain="resource" name="map" value="8GiB"/>
<policy domain="resource" name="disk" value="16GiB"/>
<policy domain="resource" name="area" value="512MP"/>
<policy domain="resource" name="width" value="64KP"/>
<policy domain="resource" name="height" value="64KP"/>

或者只对单次运行生效,不改任何文件

magick -limit memory 4GiB -limit map 8GiB -limit disk 16GiB \
  input.tif -resize 2000 output.jpg

环境变量也可以,在 CI 里很方便:

export MAGICK_MEMORY_LIMIT=4GiB
export MAGICK_DISK_LIMIT=16GiB
export MAGICK_AREA_LIMIT=512MP

内存和磁盘限制是怎么配合的

ImageMagick 先把像素缓存放内存里,到达 memory 上限后改用内存映射文件(上限是 map),再超就退到普通磁盘(上限是 disk)。所以把 memory 设得很小、disk 设得很大并不会失败 —— 它只是变得极慢。如果一个本该几秒的任务跑了几分钟,多半就是在磁盘缓存上打转。

disk 设成 0 会让它直接失败而不是慢慢退化。在延迟可预测比「无论如何都要跑完」更重要的服务器上,这是个合理选择。

与其放宽限制,不如减少工作量

  • 按缩小后的尺寸读取。 JPEG 可以直接按比例解码:magick -define jpeg:size=2000x2000 huge.jpg -resize 1000 out.jpg,全程不会分配完整尺寸的图像。
  • -thumbnail 它会先预缩放再做完整 resize,内存占用远小于 -resize
  • 限制线程数。 -limit thread 2。每个线程都有自己的开销,在内存受限的容器里线程少反而更快。
  • 逐页处理。 大的多页 PDF 请循环处理 input.pdf[n],不要一次载入全部页面。

在容器里

ImageMagick 读的是宿主机的内存,不是容器的 cgroup 限制,所以它会尝试申请超出容器允许的量,然后被 OOM 杀掉。在 Dockerfile 或启动脚本里显式设置这些限制,不要依赖默认值。


相关页面

Copied