J'essaye de copier beaucoup d'images avec Java ImageIO
. Chaque copie redimensionne l'image originale. Comme la taille de l'ensemble d'images est énorme (60 000). J'essaie d'utiliser multi thread pour résoudre le problème. Voici le code:java.lang.OutOfMemory Exception avec l'image multithread Générer
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
effectue le travail de copie. Il lit une image dans BufferedImage
, la redimensionne en une nouvelle BufferedImage
et écrit enfin dans un fichier JPEG
.
ImageWorker
le travail thread. Il est exécuté par les threads de travail dans le ExecuteServive
.
ImageGenerate
fait le travail d'expédition. Il lit tous les fichiers image dans le args(0)
(premier argument), génère une nouvelle largeur et hauteur aléatoires et soumet un nouveau travail à pool
.
Compilez et exécutez: scalac ImageGenerate.scala
scala generate.image.ImageGenerate test
. Les tailles d'images sont en moyenne 150kb.
En cours d'exécution, le programme lance java.lang.OutOfMemoryError
. Parfois, il existe une erreur Exception in thread "pool-1-thread-36" java.lang.OutOfMemoryError: GC overhead limit exceeded
.
Si je règle le paramètre -J-Xmx2048m
, le programme fonctionnera sans problème. Cependant, je ne fais que 400 images. Y a-t-il une optimisation pour mon code?
Merci de partager votre idée, meilleurs voeux.
Merci de partager votre idée. Je pense que mes soumissions de tâches à pool de threads ne sont pas contrôlées par le flux. Et la mémoire s'épuise quand il existe trop de tâches en attente dans 'ExecuteService'. Par conséquent, j'utilise un sémaphore pour limiter la vitesse des soumissions. Et ça marche beaucoup. – jiexray