Java清除集合不释放堆

标签 java memory-leaks garbage-collection set

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

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

这是程序:

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!");
}

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

在我作为程序员的职业生涯中,我从未像现在这样对问题如此困惑。我希望我能够解决这个问题,而不必用 C++ 重写所有内容,这真的很糟糕,因为到目前为止,在我处理它的几个月里,该程序已经变得异常庞大。

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

最佳答案

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

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

(但是如果 JVM 确实认为堆太大,它会返还一些内存。最终。我认为在这种情况发生之前你至少需要 2 个完整的 GC 周期......)

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

关于Java清除集合不释放堆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44856016/

相关文章:

memory-management - iOS 7 内存问题

Javascript - 垃圾收集器计时器?

java - Android - 向上滑动 FrameLayout 并让它停止

java - Linux 中的 native 内存使用率似乎比通过 JVM 本身(例如通过 JConsole)观察到的要高得多

javascript - Jquery/Javascript 内存泄漏

java - 为什么不显式调用 finalize() 或启动垃圾收集器?

.net - 如何检测 GC.Collect() 是否手动运行?

java - 如果我想让它们阻塞,为什么不在 EDT 上运行长任务

java - 在 Spring MVC 2.5 的 OnSubmit 中获取错误的 refreanceData

c++ - 在对象的 d-tor 期间检测内存泄漏