1. 问题背景及bug日志
上传图片时,偶现 OutOfMemoryError,截取部分记录日志如下
Caused by: java.lang.OutOfMemoryError: Java heap space
at java.awt.image.DataBufferInt.<init>(DataBufferInt.java:75)
at java.awt.image.Raster.createPackedRaster(Raster.java:467)
at java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1032)
at java.awt.image.BufferedImage.<init>(BufferedImage.java:324)
at cn.hutool.core.img.ImgUtil.copyImage(ImgUtil.java:1261)
at cn.hutool.core.img.ImgUtil.copyImage(ImgUtil.java:1230)
at cn.hutool.core.img.ImgUtil.toBufferedImage(ImgUtil.java:1205)
at cn.hutool.core.img.ImgUtil.toBufferedImage(ImgUtil.java:1183)
at cn.hutool.core.img.ImgUtil.write(ImgUtil.java:1566)
at cn.hutool.core.img.ImgUtil.write(ImgUtil.java:1547)
at cn.hutool.core.img.ImgUtil.writeJpg(ImgUtil.java:1470)
at cn.hutool.core.img.ImgUtil.scale(ImgUtil.java:163)
at cn.hutool.core.img.ImgUtil.scale(ImgUtil.java:149)
at cn.hutool.core.img.ImgUtil.scale(ImgUtil.java:108)
2. 分析思路以及问题重现
查看异常堆栈的代码,发现错误在代码中
// DataBufferInt.java:75
public DataBufferInt(int size) {
super(STABLE, TYPE_INT, size);
data = new int[size]; // 报错行
bankdata = new int[1][];
bankdata[0] = data;
}
// Raster.java:467
case DataBuffer.TYPE_INT:
d = new DataBufferInt(w*h); // size 等于图片的宽高之积
图片的宽高很大,但图片大小可能不大
使用一张2.1M、19200 * 1080 像素的图片进行测试,问题复现
在DataBufferInt.java:75,需要分配 4 * 19200 * 1080 个字节,约 79.1015625 M, 已经超过剩余堆内存,故报错。
3. 解决方案
对于图片的宽高进行限制
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
BufferedImage img = ImageIO.read(file.getInputStream());
if (img.getWidth() > 1920 || img.getHeight() > 1920) {
throw new InvalidParameterException("图片宽高不能超过1920像素");
}