java.lang.OutOfMemoryError:将13k .png图像拼接在一起时的Java堆空间

我有13255个图像,每个240 x 240像素宽,最大的15,412字节大小和最小的839字节。

我试图循环文件夹将每个文件添加到File []。 一旦我有一个每个图像的数组,然后我将它们放在BufferedImage []中,准备好循环并绘制到由每个图像组成的更大的单个图像上。

每个图像都以。的forms命名

Image xy.png

但是,我一直以java.lang.OutOfMemoryError:Java堆空间错误结束。 我不知道为什么。 我已经尝试通过向Eclipse的目标末尾添加参数来更改JVM可用内存的大小。 以下是我用过的内容:

IDE's\eclipse-jee-juno-SR2-win32-x86_64\eclipse\eclipse.exe -vmargs -Xms64m -Xmx1024m 

 IDE's\eclipse-jee-juno-SR2-win32-x86_64\eclipse\eclipse.exe -vmargs -Xms64m -Xmx4096m 

两者都没有效果。 我也进入了控制面板 – >程序 – > Java,并改变了那里可用的内存量。

这是我写的方法:

 public static void merge_images() throws IOException { int rows = 115; int cols = 115; int chunks = rows * cols; System.out.println(chunks); int chunkWidth, chunkHeight; int type; // fetching image files File[] imgFiles = new File[chunks]; int count = 0; for (int j = 1; j <= 115; j++) { for (int k = 1; k <= 115; k++) { imgFiles[count] = new File("G:\\Images\\Image " + j + "-" + k + ".png"); count++; } } System.out.println(imgFiles.length); // creating a buffered image array from image files BufferedImage[] buffImages = new BufferedImage[chunks]; for (int i = 0; i < chunks; i++) { buffImages[i] = ImageIO.read(imgFiles[i]); System.out.println(i); } type = buffImages[0].getType(); chunkWidth = buffImages[0].getWidth(); chunkHeight = buffImages[0].getHeight(); // Initializing the final image BufferedImage finalImg = new BufferedImage(chunkWidth * cols, chunkHeight * rows, type); int num = 0; for (int i = 0; i < rows; i++) { for (int k = 0; k < cols; k++) { finalImg.createGraphics().drawImage(buffImages[num], null, chunkWidth * k, chunkHeight * i); num++; } } System.out.println("Image concatenated....."); ImageIO.write(finalImg, "png", new File("fusions.png")); System.out.println("Image Saved, Exiting"); } 

在这里的打印线

 for (int i = 0; i < chunks; i++) { buffImages[i] = ImageIO.read(imgFiles[i]); System.out.println(i); } 

它总是停在7320点左右。

这是确切的控制台打印输出

 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.awt.image.DataBufferByte.(Unknown Source) at java.awt.image.ComponentSampleModel.createDataBuffer(Unknown Source) at java.awt.image.Raster.createWritableRaster(Unknown Source) at javax.imageio.ImageTypeSpecifier.createBufferedImage(Unknown Source) at javax.imageio.ImageReader.getDestination(Unknown Source) at com.sun.imageio.plugins.png.PNGImageReader.readImage(Unknown Source) at com.sun.imageio.plugins.png.PNGImageReader.read(Unknown Source) at javax.imageio.ImageIO.read(Unknown Source) at javax.imageio.ImageIO.read(Unknown Source) at main.merge_images(main.java:48) at main.main(main.java:19) 

任何我出错的想法都将不胜感激。

问候,

杰米

您不需要将所有块图像保留在内存中。 您可以逐个阅读它们并在最终循环中绘制到最终图像,如下所示:

 for (int i = 0; i < rows; i++) { for (int k = 0; k < cols; k++) { BufferedImage buffImage = ImageIO.read(imgFiles[num]); finalImg.createGraphics().drawImage(buffImage, null, chunkWidth * k, chunkHeight * i); num++; } } 

这将节省至少一半的内存。

你需要增加你的程序的最大内存,而不是我假设不需要更多内存的eclipse的最大值。

在eclipse中有一个选项可以更改VM参数(我不知道它是因为我多年没有使用它)

您需要能够加载所有未压缩的图像。 这意味着您至少需要13225 * 240 * 240 * 4个字节。 这只是超过3 GB。 如果您先加载所有图像,至少需要加倍。 我建议你使堆至少4 – 8 GB。

看起来每个人都在提供更简单,资源消耗更少的解决方案。 让我试试我的:

 public static void merge_images() throws IOException { int rows = 115; int cols = 115; System.out.println(rows * cols); // Initializing the final image BufferedImage finalImg = null; for (int i = 0; i < rows; i++) { for (int k = 0; k < cols; k++) { BufferedImage bufferedImage = ImageIO.read(new File("G:\\Images\\Image " + i + "-" + k + ".png")); int chunkWidth = bufferedImage.getWidth(); int chunkHeight = bufferedImage.getHeight(); if (finalImg == null) { finalImg = new BufferedImage(chunkWidth * cols, chunkHeight * rows, bufferedImage.getType()); } finalImg.createGraphics().drawImage(bufferedImage, null, chunkWidth * k, chunkHeight * i); } } System.out.println("Image concatenated....."); ImageIO.write(finalImg, "png", new File("fusions.png")); System.out.println("Image Saved, Exiting"); } 

尝试使用-Xmx1024m运行JVM或使用更大的值运行JVM。 该值是堆大小。

 java -Xmx1024m -jar app.jar 

此外,您可以在IDE中增加此值。

正如hoaz指出的那样(非常感谢)我采取的步骤太多了。 我的解决方案如下:

 public static void merge_images() throws IOException { int rows = 115; // we assume the no. of rows and cols are known and each // chunk has equal width and height int cols = 115; int chunks = rows * cols; System.out.println(chunks); // fetching image files File[] imgFiles = new File[chunks]; int count = 0; for (int j = 1; j <= 115; j++) { for (int k = 1; k <= 115; k++) { imgFiles[count] = new File("G:\\Images\\Image " + j + "-" + k + ".png"); count++; } } // Initializing the final image BufferedImage finalImg = new BufferedImage(240 * cols, 240 * rows, 13); int num = 0; for (int i = 0; i < rows; i++) { for (int k = 0; k < cols; k++) { BufferedImage buffImage = ImageIO.read(imgFiles[num]); finalImg.createGraphics().drawImage(buffImage, null, 240 * k, 240 * i); num++; } } System.out.println("Image concatenated....."); ImageIO.write(finalImg, "png", new File("fusions.png")); System.out.println("Image Saved, Exiting"); } 

基本上我所做的是删除BufferedImage [],然后在构建最终图像时,在嵌套for循环期间创建一个新的BufferedImage。 我没有使用变量,而是硬编码了图像的边界和每个图像的类型。

谢谢你指出我正确的方向hoaz。

问候

杰米