为什么这个java程序总是以内存不足结束

为什么这个java程序总是以内存不足结束,java,garbage-collection,Java,Garbage Collection,我的java版本如下 java version "1.8.0_121" Java(TM) SE Runtime Environment (build 1.8.0_121-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode) import java.util.concurrent.ThreadLocalRandom; public class Test { static class DummyObj

我的java版本如下

java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
import java.util.concurrent.ThreadLocalRandom;

public class Test {

    static class DummyObj {
        public String t1;
        public Integer t2;
        public Long t3;
        public Double t4;

        public DummyObj() {
            int i = ThreadLocalRandom.current().nextInt(10000);
            t1 = "t1t1t1" + i;
            t2 = 222 + i;
            t3 = 3333L + i;
            t4 = 44444.0 + i;
        }
    }

    void f1() {
        for (int i=0; i<100; ++i) {
            DummyObj t0 = new DummyObj();
            if (8 == ThreadLocalRandom.current().nextLong(1000000))
                System.out.println(t0.t3);
        }
    }

    public static void main(String... arg) {
        Test t0 = new Test();
        while (true) {
            t0.f1();
            try {
                Thread.sleep(2L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
};
我的程序非常简单。代码如下

java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
import java.util.concurrent.ThreadLocalRandom;

public class Test {

    static class DummyObj {
        public String t1;
        public Integer t2;
        public Long t3;
        public Double t4;

        public DummyObj() {
            int i = ThreadLocalRandom.current().nextInt(10000);
            t1 = "t1t1t1" + i;
            t2 = 222 + i;
            t3 = 3333L + i;
            t4 = 44444.0 + i;
        }
    }

    void f1() {
        for (int i=0; i<100; ++i) {
            DummyObj t0 = new DummyObj();
            if (8 == ThreadLocalRandom.current().nextLong(1000000))
                System.out.println(t0.t3);
        }
    }

    public static void main(String... arg) {
        Test t0 = new Test();
        while (true) {
            t0.f1();
            try {
                Thread.sleep(2L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
};
程序总是会因OutOfMemoryError而崩溃

有人知道gc为什么不能释放内存吗


除此之外,我做这个实验是为了了解Java垃圾收集器是如何工作的(因此这不是某种“生产代码”-它是为了显示GC“正在完成它的工作”)。

首先,您运行的JVM内存为8MB。对于Java应用程序来说,这就像“什么都没有”

然后,您将以高速率创建新对象。是的,有一些睡眠,但你的代码仍然只是一直在创建垃圾。如果代码的唯一目的是创建垃圾,那么您希望任何垃圾收集器如何跟上这一步

这就是重点:垃圾收集不是魔术。它仍然需要时间才能发生。当你结合

  • 超级少内存开始
  • 代码除了创建垃圾和睡眠之外什么都不做
您的应用程序迟早会耗尽内存

当您声明您“想通过测试了解”GC如何工作时。。。这个问题的答案甚至更短:你不能。垃圾收集是一个高级、复杂的主题。你绝对不能通过编写这样或那样的小测试用例来“学习”它是如何工作的。现代的Java垃圾收集器做了无数不同的事情。请记住:这项技术经过20多年的研究。你可能通过测试观察到的效果不会给你足够的信息来学习任何东西。你就像一个人在一个巨大的房间里试图理解所有的事情,而在外面,试图透过钥匙孔看


你必须在这里咬紧牙关——意思是:你必须学习文档和教程。启动或直接启动,这有很多深入的答案。)

对于初学者来说,
-Xmx8m
将堆空间限制为8兆字节。这是一个很小的内存量。请尝试使用
-Xmx512m
。注意Java命名约定。类名应该以大写字母开头,即使对于命名问题也是如此。使用人类可读的标识符。Minimal并不意味着你应该使用没有任何意义的名称。这是Stackoverflow而不是Codegolf。这些人不是代码高尔夫球手。谢谢@GhostCat。让我试试更大的内存。我写这个程序只是因为我想测试gc是如何工作的。如果不创建垃圾,我如何进行测试?@SeanLin我更新了我的答案。基本上,要点是:您不能通过“测试”来“学习”GC工作。你必须首先做大量的学习。我试图将内存增加到32m,不再出现内存不足的情况。@SeanLin我想:一旦你删除睡眠语句,你就会再次看到它们;-)“这仍然需要时间。当你将[…]代码组合在一起时,除了创建垃圾和睡眠之外,你的应用程序迟早会耗尽内存。”这完全是错误的。暂停收集器会很高兴地减慢应用程序的速度,因为它完成了跟上分配所必需的工作。(模开销限制超过启发式,但可以关闭)。只有当收集器在所有努力(包括一些英勇行为)失败后无法满足分配请求,或者显然无法满足时,您才会收到OOM。