2012-04-16 65 views
4

我的申請基本上是photo browser。我的方法(不要判斷我,我是新來的java)是有一個ArrayList填充BufferedImages,然後將圖像添加到JList(左)。java堆內存問題

這是我得到的圖像:

private void getFullImage() { 

     BufferedImage im = null;   


     ImageReader imageReader = null; 
      try { 
       System.out.println("Loading "+original+"..."); 
       String suffix = Utils.getFileExt(original.getName(), "jpg"); 
       @SuppressWarnings("rawtypes") 
       Iterator readers = ImageIO.getImageReadersBySuffix(suffix); 
       imageReader = (ImageReader)readers.next(); 
       imageReader.setInput(new FileImageInputStream(original)); 
       im = imageReader.read(0); 
       imageReader.dispose(); 
      } catch (Exception e) 
      { 
       e.printStackTrace(); 
      } 

     this.img = im; 
    } 

,然後,我拿來所有的數據後,我將圖像添加到我的JList

Vector vector = new Vector(); 
    JPanel container = null; 
    PhotoPanel pp = null; 
    Photo p = null; 
    for(int i=0;i<files.length;i++) 
    { 
     p = new Photo(files[i]); 
     pp = new PhotoPanel(p); 
     container = new JPanel(new BorderLayout()); 
     container.add(pp,BorderLayout.CENTER); 
             container.setBorder(BorderFactory.createTitledBorder(p.getTitle())); 
           vector.addElement(container); 
    } 
    plist.setListData(vector); 

如果我有例如10個文件,該應用程序工作得很好。問題是,當我有更多的圖像顯示。然後我會得到一個例外:Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space。所以,我知道我的方法非常糟糕,我想知道我應該如何拍攝和存儲所有圖像,並將它們顯示在JList中。也許使用緩存?我讀了一些關於SoftReference的內容,但我真的不知道如何使用它。謝謝。

+0

@Andrew會推動邊界,但仍然不適用於任意數量的照片。 – 2012-04-16 13:13:57

+0

@Jakub我認爲[@TheLima](http://stackoverflow.com/a/10174948/418556)釘了它。噪音已刪除。 – 2012-04-16 13:22:51

回答

5

有該問題的兩個主要可能的原因:


第一,和我張貼更多的不是你的情況的實際原因的警告,是數據的過量正在與System.out.println()控制檯上打印。

我不確定它是否僅適用於NetBeans或所有開發工具。但無論哪種方式,它都需要一個真正荒謬的打印量來觸發它,而且我懷疑你有很多文件正在加載。

不管怎麼說,如果你對System.out.println("Loading "+original+"...");系列的意圖是用於永久/生產日誌記錄,而不是爲了開發/調試目的而暫時放置代碼,那麼你最好使用正確的Logger。您可以閱讀this SO answer中的TL版DR指令,並且可以通過此處提供的鏈接進一步閱讀,包括官方文檔。


另一個原因,這當然是你的,因爲你有太多的數據在同一時間加載。解決方案是:

  1. 縮小圖像(縮略圖),並只顯示所選圖像的全尺寸版本。請注意,這是一種快速解決方法,不建議使用因爲它可能仍然是太多的系統承受。
  2. 只有在加載的界面的可見部分存在圖像(或所述圖像的縮略圖,用於組合的最佳解決方案),並加載新圖像(並卸載其他圖像),因爲界面被導航。
+0

通過增加分配給應用程序的堆空間,您可以通過第一種技術「進一步推進邊界」,但第二種方法要好得多。 +1 – 2012-04-16 13:25:02

+0

好的,我該如何採取第二種方法? – Teo 2012-04-16 13:39:44

+0

當用戶滾動瀏覽可用圖像時,刪除一個圖像並添加另一個圖像。或者當用戶滾動時加載x圖像並僅顯示x-2,當您顯示一個已經加載但未顯示的圖像時再加載一個圖像。 – 2012-04-16 17:43:32

0

我在大圖片(儘管在SWT中)掙扎了很多,而那些OutOfMemory和NoMoreHandles(如果沒有足夠的內存,這甚至可能發生)是一場噩夢。我認爲沒有辦法,保持大的圖像或在內存中有很多圖像。我同意Andrew的評論,但只是想補充一點,根據您的要求,您可以嘗試擴展畫布(或Swing中的任何內容),並直接在其上繪製圖像,而不將其保留在內存中(類似於PaperClips#打印預覽)。當然,你需要進行一些計算來正確地佈局圖像,但我認爲,在這種情況下,你可能會克服你的內存問題(但是還會遇到其他問題:))