我有Java应用程序,它密集地使用2D浮点数组(float[][]数组),它实际上在黑色背景上保存图像。两个维度都是相等的(平方)并且是 2 的幂(大多数是 256、512、1024),因此靠近边界的区域在大多数情况下为零。
将大小等于 2 的幂可以提高性能(有一些 FFT)并降低这些阵列上操作的复杂性,例如旋转等。最近,我在6Gb的机器上遇到了此应用程序缺乏堆的问题。根据我的计算 - 此应用程序的内存消耗应该高达 2-3Gb,而达到 4-5Gb(在 Windows 任务管理器中查找)。我使用了"YourKit"分析器,它表明这些浮点数组确实占用了大部分内存,但是,这些浮点数组的总粗略大小应该像 1.3Gb 一样(嗯,我知道由 JVM 决定如何存储数据,但我没想到内存消耗的差异有 2-3 倍)。
我试图使用 Snappy 压缩器即时压缩/解压缩数据(内存消耗下降到 3.5Gb),但性能下降了几次,这不是很可以接受。此外,当用 BufferedImage 替换这些浮点数 [][] 时,我正在测试性能,但性能非常差。
因此,还有 2 种方法可以减少内存消耗:1) 为 float[][] 数组编写包装器以节省"零"元素(有很多"空"行和列)2)远离"2次方"
这两种方式都需要相当多的编码/重构,所以当我在考虑"成为或不成为"时 - 伙计们,你可能对这个问题有更好的线索吗?
谢谢!
FFT 需要一个复数组,其大小是真实数据数组的两倍,即使您从输入端的实数组转换回最后的幅度数组也是如此。 这可能占内存使用量大于预期的 2 倍。
稀疏数组不适用于 FFT,因为 FFT 中的中间步骤几乎总是会填充整个复杂数组。
许多现代高性能FFT库,例如基于FFTW的库,可以非常有效地处理FFT长度,而不仅仅是2的幂(任何长度都是小素数的乘积都可以非常有效地处理FFT)。 这可以为许多尺寸节省大量 2D 填充。
经过更详细的调查 - JVM似乎使用"UnlockEperimentalFeatures"和"use GC1"标志启动。结果 - 有相当多的 NOT 垃圾回收"无法访问"的 BufferedImage 栅格(其中包含 byte[] 数组)。当从"YourKit"priofiler 调用 GC 时 - 那些从堆中删除的对象(这对我来说当然是不可接受的方式,因为我期望 JVM 会自己管理堆)。
我要感谢所有花时间帮助我的人。特别感谢 Jim Garrison(看起来我只是将内存需求推迟了一段时间,删除了上面提到的标志,但是当更多的数组开始发挥作用时 - 购买更多内存将是避免性能损失的最简单方法。