带有多线程图像生成的java.lang.OutOfMemory异常

时间:2017-08-15 03:23:04

标签: multithreading scala out-of-memory javax.imageio

我正在尝试使用Java ImageIO复制大量图像。每个副本都会调整原始图片的大小。由于图像集的大小很大(60,000)。我尝试使用多线程来解决问题。这是代码:

package generate.image

import scala.util.Random._
import scala.math._
import java.io.File
import java.io.PrintWriter
import java.util.concurrent.{ExecutorService, TimeUnit, Executors}
import java.awt.Image
import java.awt.image.BufferedImage
import javax.imageio.ImageIO

class ImageResizer{
    def resizeImage(srcImgPath: String, distImgPath: String, width: Int, height: Int){
        val srcFile: File = new File(srcImgPath)
        val srcImg: Image = ImageIO.read(srcFile)
        val buffImg: BufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)

        buffImg.getGraphics().drawImage(
                srcImg.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0,
                0, null
            )
        ImageIO.write(buffImg, "JPEG", new File(distImgPath))
    }
}

class ImageWorker(imgSrc: String, imgName: String, width: Int, height: Int) extends Runnable{
    override def run(): Unit = {
        val resizer = new ImageResizer()
        resizer.resizeImage(imgSrc, imgName, width, height);
    }
}

object ImageGenerate {

    def main(args:Array[String]): Unit = {
        // parameters
        val dirName = args(0)
        val images = new File(dirName).listFiles.filter(_.getName.endsWith(".JPEG"))
        val imgCnt = images.length


        // threadpool
        val pool = Executors.newFixedThreadPool(25)


        // copy with norm
        for(i <- 0 until imgCnt){
            for(cnt <- 1 to 20){
                val width = nextInt(200) + 300
                val height = nextInt(200) + 300
                val imgSrc: String = images(i).getAbsolutePath
                val imgName: String = "img/%s_%d_%d_%d.JPEG".format(splitFilename(images(i).getName), width, height, cnt)
                pool.execute(new ImageWorker(imgSrc, imgName, width, height))
            }
        }


        pool.shutdown()
        pool.awaitTermination(Long.MaxValue, TimeUnit.NANOSECONDS)
    }

    // split file name
    def splitFilename(fileName: String) = {
        fileName.substring(0, fileName.lastIndexOf("."))
    }

}

ImageResizer复制工作。它将图像读入BufferedImage,将其大小调整为新的BufferedImage,最后写入JPEG文件。

ImageWorker线程有效。它由ExecuteServive中的工作线程执行。

ImageGenerate执行调度工作。它会读取args(0)(第一个arg)中的所有图像文件,生成新的随机宽度和高度,并将新作业提交给pool

编译并运行:scalac ImageGenerate.scala scala generate.image.ImageGenerate test。图像的大小平均为150kb。

正在运行,程序抛出java.lang.OutOfMemoryErrorError Image 有时会出现Exception in thread "pool-1-thread-36" java.lang.OutOfMemoryError: GC overhead limit exceeded错误。

如果我设置参数-J-Xmx2048m,程序将顺利运行。但是,我只运行了400张图像。我的代码有优化吗?

感谢您分享您的想法,祝福。

1 个答案:

答案 0 :(得分:1)

您应该致电dispose()

像这样(未经测试)

  val graphics = buffImg.getGraphics()
  graphics.drawImage(
    srcImg.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0,
    0, null
  )
  ImageIO.write(buffImg, "JPEG", new File(distImgPath))
  graphics.dispose()