【发布时间】:2019-10-01 20:35:24
【问题描述】:
总结
- 我正在读取一个包含图像数据的大型二进制文件。
- 对数据执行累积计数切割分析[它需要另一个与图像大小相同的数组]。
- 数据在 0 到 255 之间拉伸,存储在
BufferedImage中的像素一个像素,以在 JPanel 上绘制图像。 - 在此图像上,使用
AffineTransform执行缩放。
问题
-
小图像(<.5gb>
1.1 当我增加执行缩放的比例因子时,在
点异常被抛出:-
java.lang.OutOfMemoryError: Java 堆空间。
下面是用于缩放的代码-
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 方法只是因为某种原因停止了。我尝试以低分辨率加载图像,其中读取像素并且跳转/跳过了少数列和行。但问题是如何决定随着图像大小的变化要跳过多少像素,因此我无法决定如何决定 jump 参数。
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++;
}
问题是决定要跳过多少列和行,即应该设置什么跳转值。
- 我尝试设置 Xmx,但图像大小不同,我们cannot dynamically set 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();
}
得到以下结果
Memory Allocation
这种方法失败了,因为可用内存随着我代码的使用而增加。因此,我无法做出跳跃的决定。
预期结果
一种在加载图像之前访问可用内存量的方法,以便我可以使用它来决定跳转的值。是否有其他选择来决定 jump 值(即,我可以降低多少分辨率?)。
【问题讨论】:
-
请在您的问题中添加您尝试过的 Xmx 值。
-
4.将 Xmx 设置为任意大的数字(100 GB)怎么样?在这种情况下,当系统无法提供时,JVM 将简单地死掉。用oracle JVM获取系统内存的方法在这里stackoverflow.com/questions/5512378/…。但是,如果您不需要内存中的整个图像(我猜它是原始图像?)为什么不简单地逐行(或逐像素)读取它。 CCC 不需要内存 IIRC 中的整个图像
-
如果你需要内存中的整个图像怎么办。要在 Panel 上使用 Graphics 绘制它,您需要整个 Image,对吧?
-
@Ellen Spertus 使用手动设置 Xmx 值意味着,您不能像上面提到的那样拥有任意大的图像。另外,我们可以在启动 JVM 后设置 Xmx 值吗?如果出现无法重启 JVM 的场景怎么办?
-
@EllenSpertus 我已在问题中添加了值。
标签: java graphics2d