概述
- 我正在读取一个包含图像数据的大型二进制文件。
- 对数据执行累计计数剪切分析[需要使用与图像大小相同的另一个数组]。
- 将数据在0到255之间拉伸,并逐像素存储在
BufferedImage
中,以在JPanel上绘制图像。 - 在这个图像上,使用
AffineTransform
进行缩放。
问题
小图片(<0.5GB)
1.1 当我增加缩放比例进行缩放时,达到一定点后就会抛出异常:
java.lang.OutOfMemoryError: Java heap space.
以下是用于缩放的代码-
scaled = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g2d = (Graphics2D)scaled.createGraphics();
AffineTransform transformer = new AffineTransform();
transformer.scale(scaleFactor, scaleFactor);
g2d.setTransform(transformer);
- 加载大图( >1.5GB)
- 当加载巨大图像( >1.5GB)时,会出现与1.1中相同的异常,即使图像已经足够小。有时候我也会遇到同样的错误。
尝试的解决方案
- 我尝试使用BigBufferedImage代替BufferedImage来存储伸展数据。
BigBufferedImage image = BigBufferedImage.create(newCol,newRow, BufferedImage.TYPE_INT_ARGB);
但是它无法传递给
g2d.drawImage(image, 0, 0, this);
因为JPanel的repaint方法出了一些问题。我尝试以低分辨率加载图像,在这里像素被读取和少数列和行被跳过。但问题是如何决定要跳过多少像素,因为图像大小不同,因此我无法决定如何决定“跳跃”参数。
MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY,0, inChannel.size());
buffer.order(ByteOrder.LITTLE_ENDIAN);
FloatBuffer floatBuffer = buffer.asFloatBuffer();
for(int i=0,k=0;i<nrow;i=i+jump) /*jump is the value to be skipped, nrow is height of image*/
{
for(int j=0,l=0;j<ncol1;j=j+jump) //ncol is width of image
{
index=(i*ncol)+j;
oneDimArray[(k*ncolLessRes)+l] = floatBuffer.get(index);//oneDimArray is initialised to size of Low Resolution image.
l++;
}
k++;
}
问题是要决定跳过多少列和行,即应设置什么值的jump。
- 我尝试设置Xmx,但图像大小会变化,而且我们无法动态设置Xmx值。以下是一些值 -
table, th, td {
border: 1px solid black;
}
<table style="width:100%">
<tr>
<th>Image Size</th>
<th>Xmx</th>
<th>Xms</th>
<th>Problem</th>
</tr>
<tr>
<td>83Mb</td>
<td>512m</td>
<td>256m</td>
<td>working</td>
</tr>
<tr>
<td>83Mb</td>
<td>3096m</td>
<td>2048m</td>
<td>System hanged</td>
</tr>
<tr>
<td>3.84Gb</td>
<td>512m</td>
<td>256m</td>
<td>java.lang.OutOfMemoryError: Java heap space
</tr>
<tr>
<td>3.84Gb</td>
<td>3096m</td>
<td>512m</td>
<td>java.lang.OutOfMemoryError: Java heap space
</tr>
</table>
try(BufferedWriter bw= new BufferedWriter(new FileWriter(dtaFile,true))){
Runtime runtime=Runtime.getRuntime();
runtime.gc();
double oneMB=Math.pow(2,20);
long[] arr= Instream.range(0,(int)(10.432*long.BYTES*Math.pow(2,20))).asLongStream().toArray();
runtime.gc();
long freeMemory= runtime.freeMemory();
long totalMemory= runtime.totalMemory();
long usedMemory= totalMemory-freeMemory;
long maxMemory= runtime.maxMemory();
String fileLine= String.format(" %9.3f %9.3f %9.3f " , usedMemory/oneMb, freeMemory/oneMB, totalMemory/oneMb, maxMemory/oneMB);
bw.write();
}
以下是获得的结果
内存分配
这种方法失败了,因为可用内存随着我的代码使用而增加。 因此,对于我来说,它将是无用的来决定跳跃的值。
预期结果
一种在加载图像之前访问可用内存量的方法,以便我可以使用它来决定跳跃的值。是否有其他的替代方法来决定跳跃值(即可以降低分辨率的程度)。