2014-09-25 5 views
0

Java 데스크톱 기반 응용 프로그램을 개발 중입니다. 여기 내 작업은 이미지를 JLabel에 넣는 것입니다. 레이블에 60 개 이상의 이미지를로드하면 자바는 "힙 공간 오류"를 표시합니다 (아래 참조).BufferdImage 힙 공간 오류

JDK의 힙 공간 크기를 늘리고 싶지 않습니다. 그냥 JLabel에 이미지를 표시 한 후 메모리를 비우고 싶습니다. BufferedImageflush()을 사용했습니다. 메모리를 지우지 않습니다. 여기

내 코드 스택 추적

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()); 
    } 

: (JPG/PNG 형식으로 압축 된 이미지 데이터보다 훨씬 더 큰)

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

+0

java.lang.OutOfMemoryError와 이외에 전체 오류 메시지를 추가) 가시성 이벤트 기간 동안 창조적 인 일을. (DataBufferByte.java:92) java.awt.image.ComponentSampleModel.createDataBuffer에서 \t (ComponentSampleModel.java:415) java.awt.image.Raster.createWritableRaster에서 \t (Raster.java:944)에서 javax의 \t .imageio.ImageTypeSpecifier.createBufferedImage (ImageTypeSpecifier.java:1073) javax.imageio.ImageReader.getDestination에서 \t (ImageReader.java:2896) com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal에서 \t (JPEGImageReader.java : 998) \t com.sun.imageio.plugins.jpeg.JPEGImageReader.read (JPEGImageReader.java:966) –

+0

'ImageIcon'을 사용하는'JLabel'은 여러분이 null 일 경우에도'img' 참조를 유지합니다 전자 참조. 다시 칠할 때마다 이미지 데이터가 다시 필요합니다. 'BufferedImage'를 flush()하는 것은 힙 메모리를 해제하지 않으므로 좋지 않습니다. 또한 JVM은 포기하고 OOME을 던지기 전에 GC를 수행해야하므로 명시적인 GC를 요청할 필요가 없습니다. 아이콘이있는'JLabel'을 없애거나 JVM 힙 크기를 늘리면됩니다. – haraldK

답변

0

디코딩 된 이미지 데이터가 어딘가에 때 개최하고있다 표시되고 어딘가에는 힙이 있습니다.

더 이상 표시되지 않는 이미지에 대한 메모리를 확보하려는 경우 (예 : 누군가가 스크롤 한 경우) 페인트 통화로 렌더링 할 수 없는지 확인해야합니다 (예 : 화면이 꺼진 경우). 그런 다음 이미지 자체를 처분 할뿐만 아니라 JLabel이 이미지 참조를 잃어 GC가 이미지를 수집 할 수 있도록해야합니다. 처분은 이미지에서 사용하는 원시 메모리 리소스를 정리하는 힌트 일 뿐이며 궁극적으로는 BufferedImage 리소스 자체가 필요합니다. GC'ed는 참조하는 모든 객체가 참조를 삭제해야 함을 의미합니다.

즉, 화면에서 스크롤 할 때 이미지 참조를 처분하고 다시 볼 수있게되면 다시로드 할만큼 충분히 영리한 사용자 지정 구성 요소가 필요합니다.

스윙이 당신을 위해이 일을하지 않을 것입니다 - 당신은 여기서 창의적으로 행동해야합니다 (어떤 일도없이 자동적으로 그렇게하지는 않을 것입니다 ... 아마 당신은 Java 힙 공간 \t을 java.awt.image.DataBufferByte에서 : componentListener를하고

+0

Riyad에게 감사드립니다. Jpanel을 사용하면 Oome 오류가 발생하지만 150 + imges에 도움이됩니다. –