2016-09-23 9 views
0

Я хочу построить гистограммы из нескольких изображений. Для выполнения этого процесса я получаю доступ к DataBufferByte . Я признаю, что GC не освобождает память после построения гистограммы. Что не так с этим кодом?Пиксельный доступ BufferedImage - утечка памяти?

import java.awt.Color; 
import java.awt.image.BufferedImage; 
import java.awt.image.DataBufferByte; 
import java.io.File; 
import java.io.IOException; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.Map.Entry; 
import java.util.concurrent.atomic.AtomicInteger; 
import javax.imageio.ImageIO; 


public class Histogram { 

    HashMap<Color,AtomicInteger> histogram; 

    public Histogram() { 
     histogram = new HashMap<>(); 
    } 

    public void build(BufferedImage image){ 

     int pixelLength = 3; 

     byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); 

     int red, green, blue; 
     Color color; 
     for (int pixel = 0; pixel <= pixels.length - pixelLength; pixel+= pixelLength) { 

      blue= ((int) pixels[pixel] & 0xff); // blue 
      green= (((int) pixels[pixel + 1] & 0xff)); // green 
      red = (((int) pixels[pixel + 2] & 0xff)); // red 
      color = new Color(red, green, blue); 
      if(histogram.containsKey(color)){ 
       histogram.get(color).incrementAndGet(); 
      } 
      else{ 
       histogram.put(color, new AtomicInteger(1)); 
      } 
     } 
     pixels = null;  
    } 

    public static void main(String[] args) { 
     String pathImage = "C://testjpg"; 
     try { 
      for (int j = 0; j < 5000; j++) { 
       BufferedImage i = ImageIO.read(new File(pathImage)); 

       Histogram h = new Histogram(); 

       h.build(i); 
       i.flush(); 

      } 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     }  
    } 
} 

спасибо за поддержку :)

+0

Прежде всего, GC не восстанавливает память немедленно, она делает это, когда она находит нужным. Во-вторых, 'flush()' BufferedImage' 'не освобождает пиксельные данные (он только очищает« поверхностные данные », что может быть кэшированным представлением в видеопамяти, вне кучи JVM). «BufferedImage», на который ссылается ваша переменная 'i', * доступен для GC * после каждой итерации вашего цикла, но это может не произойти сразу. – haraldK

+0

... или, другими словами, здесь нет ничего плохого ... :-) – haraldK

+0

okay - спасибо. Я думаю, что это очень любопытно ... Я использую код гистограммы в веб-приложении tomcat, который извлекает гистограммы из более чем 10.000 изображений в цикле. Там память увеличивается очень быстро (я не сохраняю гистограммы за это время, но tomcat занимает более 10 ГБ оперативной памяти o.o). Если я запускаю автономную программу на машине с Windows, она выглядит нормально ... –

ответ

1

ГХ не запускается автоматически, и напоминает, память только тогда, когда это необходимо. Вы можете заставить его использовать System.gc(), но будьте осторожны, чтобы не делать это слишком часто, иначе это замедлит вашу программу.

Ваш код работает нормально, и вот что я проверил:

public static void buildColorHistogram(BufferedImage image) 
{ 
final int pixelLength = 3; 

byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); 

for (int pixel=0 ; pixel < pixels.length; pixel+=pixelLength) 
    { 
    final int blue = pixels[pixel] & 0xff ; // blue 
    final int green= pixels[pixel + 1] & 0xff ; // green 
    final int red = pixels[pixel + 2] & 0xff ; // red 
    Color color = new Color(red, green, blue) ; 
     if (histogram.containsKey(color)) 
      histogram.get(color).incrementAndGet() ; 
     else 
      histogram.put(color, new AtomicInteger(1)) ; 
    } 

pixels = null ; 
} 

Будьте осторожны, что некоторые цветные изображения имеют также альфа-канал, что означает, что pixelLength будет 4 вместо 3.

Вы опорожняете гистограмму, когда закончите с ней? Потому что есть 16 миллионов комбинаций/триплетов цвета.

+0

Спасибо! Да, я использую histogram.clear() после того, как я закончил –