2017-08-15 4 views
0

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.scalascala generate.image.ImageGenerate test. Les tailles d'images sont en moyenne 150kb.

En cours d'exécution, le programme lance java.lang.OutOfMemoryError. Error Image 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.

Répondre

1

Vous devriez appellerez dispose()

Quelque chose comme ça (non testé)

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() 
+0

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