2014-09-25 157 views
0

我正在開發基於Java桌面的應用程序。在這裏,我的工作是將圖像放入JLabel。如果我將超過60張圖像加載到標籤中,則java會顯示「堆空間錯誤」(請參閱​​下面的內容)。BufferdImage堆空間錯誤

我不想增加JDK的堆空間大小。我只想在顯示JLabel中的圖像後釋放內存。我用flush()BufferedImage:它不清除內存。

這裏是我碼

public static void setImageInLabelFromBufferedImage(JLabel label, int commonWidth, int maxImageHeight, BufferedImage img) { 
    try { 

     if (img.getWidth() < commonWidth && img.getHeight() < maxImageHeight) { 
      **img = Scalr.resize(img, Scalr.Mode.AUTOMATIC, img.getWidth(), img.getHeight(), Scalr.OP_ANTIALIAS);** 
     } else { 
      if (img.getWidth() > img.getHeight()) { 
       if (img.getWidth() > commonWidth) { 
        img = Scalr.resize(img, Scalr.Mode.FIT_TO_WIDTH, commonWidth, maxImageHeight, Scalr.OP_ANTIALIAS); 
       } 
      } else if (img.getHeight() > img.getWidth()) { 
       if (img.getHeight() > maxImageHeight) { 
        img = Scalr.resize(img, Scalr.Mode.FIT_TO_HEIGHT, commonWidth, maxImageHeight, Scalr.OP_ANTIALIAS); 
       } 
      } else { 
       img = Scalr.resize(img, Scalr.Mode.FIT_EXACT, commonWidth, maxImageHeight, Scalr.OP_ANTIALIAS); 
      } 
     } 

     //BufferedImage resizedImage = Scalr.resize(img, Scalr.Mode.AUTOMATIC, commonWidth, maxImageHeight, Scalr.OP_ANTIALIAS); 
     label.setIcon(new ImageIcon(img)); 
     label.revalidate(); 
     img.flush(); 
     img = null; 
     Runtime.getRuntime().gc(); 

    } catch (Exception e) { 
     log.error("setImageInLabelFromBufferedImage==>" + e.getMessage()); 
    } 

堆棧跟蹤:

java.lang.OutOfMemoryError: Java heap space at 
java.awt.image.DataBufferByte.<init>(DataBufferByte.java:92) at 
java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:4‌​15) at 
java.awt.image.Raster.createWritableRaster(Raster.java:944) at 
javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:107‌​3) at 
javax.imageio.ImageReader.getDestination(ImageReader.java:2896) at 
com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:9‌​98) at 
com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:966) 
+0

也許除了添加完整的錯誤消息的代碼 – Chris 2014-09-25 10:08:15

+0

java.lang.OutOfMemoryError:在java.awt.image.DataBufferByte中的Java堆空間 \t。 (DataBufferByte.java:92) \t在java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:415) \t在java.awt.image.Raster.createWritableRaster(Raster.java:944) \t在的javax .imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1073) \t在javax.imageio.ImageReader.getDestination(ImageReader.java:2896) \t在com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java :998) \t at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:966) – 2014-09-25 10:40:31

+0

即使你沒有使用'ImageIcon',你的'JLabel'也會保留在'img'引用上e本地參考。每次重繪都會再次需要圖像數據。 flush()'BufferedImage'不釋放堆內存,所以它不好。在放棄和拋出OOME之前,JVM也應該做GC,所以不需要明確的GC。對我來說,你需要用Icon來擺脫一些JLabel,或者只是增加JVM堆大小。 – haraldK 2014-09-26 09:35:00

回答

0

解碼後的圖像數據(比JPG /的PNG格式的壓縮圖像數據大得多)在某處時舉行顯示,並在某個地方是堆。

如果你的意思是你想釋放不再顯示圖像的內存(例如某人已經滾過它們),你將不得不確保它們不能通過繪畫調用渲染(例如它們不在屏幕上)並且那麼你不僅需要處理圖像本身,還要確保JLabel失去它對圖像的引用,以便GC可以收集它 - 處理只是清理圖像使用的本地內存資源的一種暗示,最終你'需要BufferedImage資源本身GC'ed,這意味着任何引用它的對象都需要刪除它的引用。

這意味着您可能需要一個足夠聰明的自定義組件,以便在滾動屏幕時處理圖像引用,並在再次變爲可見時再次將其加載。

開箱即用Swing不會爲你做這件事 - 你需要在這裏發揮創意(我的意思是沒有任何工作,它不會自動執行此操作......你可以使用的ComponentListener並在能見度事件做創意的東西)

+0

感謝利雅得,如果我使用Jpanel,它也會導致OOME錯誤,但是在它幫助150 + imges後.. – 2014-10-13 12:00:35