Java 清除了集合,而不是释放堆



我目前正在开发一款游戏,并选择Java作为我的主要开发平台。我现在有点后悔,因为我遇到了我不完全理解的重大内存泄漏。到目前为止,我对Java并不陌生,但是由于某种原因,我无法理解这个错误。基本问题是我把我的游戏世界分成几部分加载,以免使用太多内存。玩家离开区域后,将设置的区域保存在地图中,从地图中删除。出于某种原因,垃圾回收器在那之后不会删除该区域,并且内存消耗量会不断增加,直到我停止游戏。根据我对垃圾收集器的理解,当不再有线程访问对象时,它应该删除堆变量,这在我的游戏中就是这种情况。

因为我的游戏引擎已经很大了,而且太复杂了,无法进行实验,所以我做了一个小的测试程序来检查我对垃圾收集器的理解是否是"垃圾;P"。(我知道我是双关语,对吧?...斯里^^(

这是程序:

public static void main(String... args) throws InterruptedException {
new Thread(() -> {
try {
Set<Long> set = new HashSet<>();
System.out.println("Saving stuff");
for (long i = 0; i < 19999999L; i++) {
set.add(i);
}
Thread.sleep(10000);
System.out.println("Clearing stuff");
set.clear();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(40000);
System.out.println("Exiting program!");
}

如您所见,我基本上只是在 HashSet 中保存一堆多头,然后清除它。为了确保多头不再被访问,它们所属的线程甚至停止。但是由于某种原因,没有释放内存。

在我作为程序员的职业生涯中,我从来没有像现在这样对一个问题感到困惑。我希望我能在不用C++重写所有内容的情况下解决这个问题,这真的很糟糕,因为到目前为止,该程序在我工作的几个月里已经变得非常大。

我很高兴你们能提供任何帮助,我真的希望我能解决这个问题, 提前谢谢你:)

不要期望 Java 应用程序在垃圾回收后将内存释放回操作系统。

JVM的正常行为是保持堆大小较大,这样它就不需要经常运行GC。 它"渴望"从操作系统请求更多内存,而"不愿意"将其归还。

(但是,如果 JVM 确实决定堆太大,它将返回一些内存。 最终。 我认为您至少需要 2 个完整的 GC 循环才能发生这种情况......

但事情是这样的。 如果您在C++中执行了相同的操作,则正常的C++分配器也很有可能不会将内存返回给操作系统。 当然,如果大数据结构的创建和破坏导致C++堆的碎片化,它将无法做到这一点。

随着时间的推移,我最近的一个3D应用程序也逐渐具有更大的内存。

我发现的原因不是垃圾回收器没有收集几何/纹理。相反,当我尝试实例化新几何时,我使用的库也在几何上创建了一个event listener,因为事件侦听器位于全局范围内,因此永远不会收集它。

我手动分离了事件侦听器,收集器正确地完成了它的工作。

希望会有所帮助

最新更新