如何在Java中处理RAM中的海量数据/图像? 总结 我正在读一个包含图像数据的大二进制文件 对数据执行累积计数切割分析[它需要另一个与图像大小相同的数组] 将存储在buffereImage中的数据逐像素拉伸到0到255之间,以便在JPanel上绘制图像 在此图像上,使用仿射变换执行缩放 问题

如何在Java中处理RAM中的海量数据/图像? 总结 我正在读一个包含图像数据的大二进制文件 对数据执行累积计数切割分析[它需要另一个与图像大小相同的数组] 将存储在buffereImage中的数据逐像素拉伸到0到255之间,以便在JPanel上绘制图像 在此图像上,使用仿射变换执行缩放 问题,java,graphics2d,Java,Graphics2d,小图像(1.5GB) 当加载一个巨大的图像(>1.5GB)时,会出现与中相同的异常 1.1,即使图像小到可以加载,有时也会出现同样的错误 尝试过的解决方案 我尝试使用替代BuffereImage来存储拉伸数据BigBufferedImage image=BigBufferedImage.create(newCol,newRow,BufferedImage.TYPE_INT_ARGB) 但无法将其传递给g2d.drawImage(image,0,0,this) 因为JPanel的重新绘制方法由

小图像(1.5GB)
  • 当加载一个巨大的图像(>1.5GB)时,会出现与中相同的异常 1.1,即使图像小到可以加载,有时也会出现同样的错误
尝试过的解决方案
  • 我尝试使用替代BuffereImage来存储拉伸数据
    BigBufferedImage image=BigBufferedImage.create(newCol,newRow,BufferedImage.TYPE_INT_ARGB)
  • 但无法将其传递给
    g2d.drawImage(image,0,0,this)
    因为JPanel的重新绘制方法由于某种原因而停止

  • 我尝试以低分辨率加载图像,读取像素,跳过/跳过很少的列和行。但问题是如何决定图像大小变化时跳过多少像素,因此我无法决定如何确定跳跃参数

  • 
    图像大小
    Xmx
    Xms
    问题
    83Mb
    512m
    256m
    工作
    83Mb
    3096米
    2048米
    系统挂起
    3.84Gb
    512m
    256m
    java.lang.OutOfMemoryError:java堆空间
    3.84Gb
    3096米
    512m
    java.lang.OutOfMemoryError:java堆空间
    
  • OutOfMemoryError
    这是自我解释-您的内存不足。也就是说,不是机器上的物理RAM,而是JVM达到了
    -xmx
    设置设置的内存分配上限
  • 当您试图将3,8GB大小的图像放入512MB内存块时,xmx设置测试没有什么意义。它不能工作-你不能把10公升的水放在5公升的瓶子里。对于内存使用,您至少需要图像x3的大小,因为您要单独存储每个像素,并且包含3个字节(RGB)。这只适用于纯图像数据。剩下的是整个应用程序和数据对象结构的开销+计算所需的额外空间,可能还有很多我没有提到,甚至我都不知道的地方
  • 您不想“动态设置”-xmx。将其设置为系统中可能的最大值(反复试验)。JVM不会占用那么多内存,除非它需要。通过额外的-X设置,您可以告诉JVM释放未使用的内存,这样您就不必担心未使用的内存被JVM“冻结”
  • 我从未从事过图像处理应用。Photoshop或Gimp是否能够打开并处理如此大的图像?也许你应该在那里寻找处理那么多数据的线索(如果有用的话)
  • 如果上面这一点只是一个幼稚的想法,因为出于科学目的,你需要它(这不是Photoshop或Gimp的目的,除非你是FlateEarther:),你将需要科学级的硬件
  • 我脑海中浮现的一件事,根本不是将图像读入记忆,而是动态地处理它。这可以将内存消耗减少到兆字节的数量级

  • 仔细查看API所建议的(
    readTile
    method)可能只读取图像区域(例如用于放大)

    您可以读取图像的特定部分,然后为显示目的以降低分辨率缩放它

    因此,在您的例子中,您可以在块中读取图像(读取图像部分,就像我们逐行从db读取数据一样)

    例如:

    // Define the portion / row size 50px or 100px
    int rowHeight = 50;
    int rowsToScan = imageHeight / rowHeight;
    if(imageHeight % rowHeight > 0) rowsToScan++;
    
    int x = 0;
    int y = 0;
    int w = imageWidth;
    int h = rowHeight;
    
    ArrayList<BufferedImage> scaledImagePortions = new ArrayList<>();
    
    for(int i = 1; i <= rowsToScan; i++) {
        // Read the portion of an image scale it
        // and push the scaled version in lets say array
        BufferedImage scalledPortionOfImage = this.getScaledPortionOfImage(img, x, y, w, h);
        scaledImagePortions.add(scalledPortionOfImage);
    
        y = (rowHeight * i);
    }
    
    // Create single image out of scaled images portions
    
    //定义部分/行大小50px或100px
    整数行高=50;
    int rowsToScan=图像高度/行高度;
    如果(imageHeight%rowHeight>0)行扫描++;
    int x=0;
    int y=0;
    int w=图像宽度;
    int h=行高;
    ArrayList ScaleImage部分=新ArrayList();
    
    对于(int i=1;我请在您的问题中添加您尝试过的Xmx值。4.在这种情况下,将Xmx设置为任意大的数字(100 GB)如何?当系统无法提供时,JVM将简单地消亡。使用oracle JVM获取系统内存的方法在这里。但是,如果您不需要内存中的整个图像(我想是原始的?)为什么不逐行(或逐像素)阅读呢.CCC不需要内存中的整个图像IIRC如果您需要内存中的整个图像该怎么办。要在面板上使用图形绘制它,您需要整个图像,对吗?@Ellen Spertus使用手动设置Xmx值意味着,您不能像上面提到的那样拥有任意大的图像。此外,我们可以在启动JVM后设置Xmx值吗?如果存在无法重新启动JVM的情况?@EllenSpertus我已在问题中添加了值。
        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++;
        }
    
    
    // Define the portion / row size 50px or 100px
    int rowHeight = 50;
    int rowsToScan = imageHeight / rowHeight;
    if(imageHeight % rowHeight > 0) rowsToScan++;
    
    int x = 0;
    int y = 0;
    int w = imageWidth;
    int h = rowHeight;
    
    ArrayList<BufferedImage> scaledImagePortions = new ArrayList<>();
    
    for(int i = 1; i <= rowsToScan; i++) {
        // Read the portion of an image scale it
        // and push the scaled version in lets say array
        BufferedImage scalledPortionOfImage = this.getScaledPortionOfImage(img, x, y, w, h);
        scaledImagePortions.add(scalledPortionOfImage);
    
        y = (rowHeight * i);
    }
    
    // Create single image out of scaled images portions