I have to make a function that receives as en entry a List<PDXObjectImage> list
and creates a small icon for each of these elements and store them in a JTable.
Now I found a way to create icons from a PDXObjectImage
without loading the whole Image so that my program does not throw OutOfMemoryError: Java heap space
:
for(int k=0;k<list.size();k++)
{
ByteArrayOutputStream output = new ByteArrayOutputStream();
list.get(k).write2OutputStream(output);
ByteArrayInputStream bais = new ByteArrayInputStream(output.toByteArray());
ImageInputStream iis = ImageIO.createImageInputStream(bais);
Iterator iter = ImageIO.getImageReaders(iis);
if (iter.hasNext()) {
ImageReader reader = (ImageReader) iter.next();
reader.setInput(iis, true, true);
ImageReadParam params = reader.getDefaultReadParam();
params.setSourceSubsampling(2.0, 2.0, 0, 0);
BufferedImage img = reader.read(0, params);
ImageIcon imageIcon = new ImageIcon(img);
model.addRow(new Object[]{imageIcon});
}
}
I managed to avoid the OutOfMemoryError: Java heap space
for a small amount of pictures in the list using readers instead of loading the images as BufferedImage
each time.
Unfortunately, I still get this error when more than 84 elements are stored in the list.
I used jvisualvm to see what objects took all the heap space and I found out it was byte[]
objects(around 85%).
The problem is clearly located where I create all the streams to get the iconImage
.
The thing is I don't know any ways of getting a ImageInputStream
without having to create new streams each time.
I tried to avoid the problem by generating all the streams in a single function :
private ImageInputStream fct(PDXObjectImage img) throws IOException{
ByteArrayOutputStream output = new ByteArrayOutputStream();
img.write2OutputStream(output);
ByteArrayInputStream bais = new ByteArrayInputStream(output.toByteArray());
return ImageIO.createImageInputStream(bais);
}
thinking that java would automatically delete objects when it reach the end of the scope.
I tried adding the following in any order possible at the end of each loop :
output.reset();
output.flush();
bais.reset();
bais.close();
iis.flush();
output=null;
bais=null;
iis=null;
System.gc();
I also tried to instantiate the streams outside the function's scope, but there is no way of setting a ByteArrayInputStream
from a byte[]
without using the new
keyword, thus creating a new object.
I still get the same error, nothing works.
I read some posts on Statements
and ResultSets
but I not found them relevant. (Maybe I am wrong)
If someone has any idea of how I could avoid this error, I would be very gratefull.
Thank you
EDIT:
I have modified my code so that I get the following :
for(int k=0;k<list.size();k++)
{
list.get(k).write2OutputStream(cbb.getOutputStream());
ImageInputStream iis = ImageIO.createImageInputStream(cbb.getInputStream());
Iterator iter = ImageIO.getImageReaders(iis);
if (iter.hasNext()) {
ImageReader reader = (ImageReader) iter.next();
reader.setInput(iis, true, true);
BufferedImage img = reader.read(0, null);
ImageIcon imageIcon = new ImageIcon(img);
model.addRow(new Object[]{imageIcon});
}
}
I have also added a listener to the reader so that it prints out the percentage of the reading done. It always goes up to 84.2% and stops.
Does anyone knows how can this be possible?