【问题标题】:Possible Memory Leak with JOGL using VBOs使用 VBO 的 JOGL 可能存在内存泄漏
【发布时间】:2011-08-12 09:59:31
【问题描述】:

我们目前正在开发一个应用程序,它可以在 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 的图片:

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

【问题讨论】:

  • +1 对于关心内存的 Java 程序员,尽管它可能是徒劳的。

标签: java opengl buffer jogl vbo


【解决方案1】:

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

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

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

【讨论】:

  • 是的,没错。也许标题是错误的。这并不是真正的内存泄漏。感谢您建议的配置文件。我们会看看!
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

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

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

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

    看的好地方是here

    这个适合你:

    -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]
    

    问候。

    【讨论】:

    • 这是 JVM 参数的一个好点。我找到了以下两个可以设置的参数:-XX:MaxHeapFreeRatio=20 -XX:MinHeapFreeRatio=10
    【解决方案4】:

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

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

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

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

    VisualVM +1

    玩得开心:)

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-03
      • 1970-01-01
      相关资源
      最近更新 更多