我们目前正在开发一种应用程序,它可以在4D中在球体/平面上显示巨大的矢量场(> 250'000)。为了加快这个过程,我们使用VBO作为顶点,法线和颜色。为了在发送到GPU之前准备数据,我们使用Buffers(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(),但没有效果。你有什么想法吗?
答案 0 :(得分:3)
内存使用量增加有多种原因。我会说它不是内存泄漏,除非每次执行此操作时内存都会增加。如果它仅在第一次出现时,可能是该库需要一些内存来加载。
我建议您在之前和之后进行堆转储或至少jmap -histo:live
以查看内存增加的位置。
如果您使用像VisualVM或YourKit这样的内存分析器,它将显示内存保留的位置和原因。
答案 1 :(得分:1)
可能没有内存泄漏,但是对象转到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]
问候。
答案 2 :(得分:1)
如果gc能够清理它,它实际上不是内存泄漏。这可能是浪费内存,但您的应用程序似乎配置为允许它使用超过800MB的堆。这是垃圾收集性能和内存使用之间的权衡。您还可以尝试使用较小的堆大小运行应用程序。
答案 3 :(得分:1)
JVM不会释放任何对象,直到它必须(例如,到达Xmx)。这是您可以在当前JVM中找到的所有GC背后的主要概念之一。它们都针对吞吐量进行了优化,即使是并发的吞吐量。我在GC图表上看不到任何异常。
如果完整GC之后使用的堆会随着时间的推移不断增长 - 如果没有 - 那么这将是一个泄漏 - >好的。
简而言之:foo = null;不会仅释放对象的引用。 GC可以随时释放内存。
也: buffer.clear()不清除缓冲区,它设置pos = 0和limit = capacity - 这就是全部。有关详细信息,请参阅javadoc。
VisualVM +1
玩得开心:)
(offtopic:如果缓冲区很大而且是静态的,你应该在permgen中分配它们.Buffers.newDirectFloatBuffer()将是最新的gluegen-rt中的那些实用方法之一)