2

我们目前正在开发一个应用程序,它可以在 4D 的球体/平面上可视化巨大的矢量场(> 250'000)。为了加快这个过程,我们对顶点、法线和颜色使用 VBO。为了在发送到 GPU 之前准备数据,我们使用缓冲区(FloatBuffer、ByteBuffer 等)。

柱面的一些数据:每个柱面使用 16 * 9 + 16 * 3 = 192 个浮点数 -> 192 * 4 字节 = 768 字节。

在发送了顶点之后,我们正在进行以下清理:

// clear all buffers
vertexBufferShell.clear();
indexBufferShell.clear();

vertexBufferShell = null;
indexBufferShell = null;

我们使用 JConsole 对其进行了监控,我们发现 GarbageCollector 没有“正确”运行。即使我们关闭柱面计数,内存也不会被释放。在 JConsole 监控工具中有一个运行 GC 的按钮,如果我们手动执行此操作,它会释放内存(如果我们加载了大量的柱面并减少了很多,有时超过 600mb 会被 GC 清理)。

这是 JConsole 的图像: JConsole 输出,按下执行 GC 按钮后,内存确实得到了清理

现在的问题是我们如何在代码中自己清理这个 Buffers?调用 clear 方法并将引用设置为 null 是不够的。我们也尝试调用System.gc()但没有任何效果。你有什么主意吗?

4

4 回答 4

3

内存使用量可能会增加的原因有很多。我会说它不是内存泄漏,除非每次执行此操作时内存都会增加。如果只是第一次出现,可能是这个库需要一些内存来加载。

我建议您进行堆转储或至少jmap -histo:live在之前和之后查看内存增加的位置。

如果您使用 VisualVM 或 YourKit 之类的内存分析器,它将向您显示内存被保留的位置和原因。

于 2011-08-12T10:09:08.373 回答
1

可能没有内存泄漏,但对象会进入Ternured(在次要 gc 中活着通过的对象所在的区域)。

您看到的这些大步骤可能Young Eden是已满的,并且在次要 gc 将活动对象移动到 Ternure.

您还可以尝试调整垃圾收集器和内存。

您可能有很多中等长度的活动对象,它们不断传递给Ternured完整 gc 中的释放它们。如果您对它们进行尺寸标注,那么这些对象将成为次要 gc。

有很多 jvm 参数可以做到这一点。

一个看的好地方就在这里

这一款适合你:

-XX:NewSize=2.125m 
Default size of new generation (in bytes) 
[5.0 and newer: 64 bit VMs are scaled 30% larger; x86: 1m; x86, 5.0 and older: 640k]

问候。

于 2011-08-12T13:59:32.847 回答
1

如果 gc 能够清理它,它并不是真正的内存泄漏。这可能会浪费内存,但您的应用似乎已配置为允许它使用超过 800MB 的堆。这是垃圾收集性能和内存使用之间的权衡。您也可以尝试使用较小的堆大小简单地运行您的应用程序。

于 2011-08-12T14:09:23.077 回答
1

JVM 将不会释放任何对象,直到它必须(例如,达到 Xmx)。这是您可以在当前 JVM 中找到的所有 GC 背后的主要概念之一。它们都针对吞吐量进行了优化,甚至是并发的。我在 GC 图上没有看到任何异常。

如果在完整 GC之后使用的堆会随着时间的推移不断增长 - 如果它没有 -> 一切都很好,那将是一个泄漏。

简而言之: foo=null; 不会只释放对象的引用。GC 可以随时释放内存。

另外: buffer.clear() 不清除缓冲区,它设置 pos=0 和 limit=capacity - 仅此而已。有关更多信息,请参阅 javadoc。

视觉虚拟机 +1

玩得开心 :)

(题外话:如果缓冲区很大且是静态的,则应在 permgen 中分配它们。Buffers.newDirectFloatBuffer() 将是最新的gluegen-rt 中的实用方法之一)

于 2011-08-12T22:40:32.163 回答