当前位置: 首页 > 知识库问答 >
问题:

为什么这个小Java程序使MacOS重新启动?

唐彦
2023-03-14

代码如下

Set<Thread> threads = new HashSet<>();

Runnable r = () -> {
    try {
        Thread.sleep(Long.MAX_VALUE);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
};

for (int i = 0; i < 20000; i++) {
    Thread t = new Thread(r);
    threads.add(t);
    t.start();
    if (i % 100 == 0) {
        System.out.println(i);
    }
    Thread.sleep(2);
}

当执行时,我开始看到如下值

0
100
200
300

正如所料,直到我看到:

3900
4000
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Thread.java:717)
    at App.main(scratch.java:24)
Java HotSpot(TM) 64-Bit Server VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal SIGINT to handler- the VM may need to be forcibly terminated

但是过了一会儿(10-20秒左右)MacOS决定重新启动。我在这里看到的重新启动的原因是什么?主线程抛出异常,但进程有大约4000个线程Hibernate导致...操作系统中的什么?这是内存溢出还是与操作系统的任务调度程序有关?

MacOS version: 10.14.3 (18D109)
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)

共有3个答案

戈嘉慕
2023-03-14

今天我偶然发现了同样的问题。下面是一些在10.15.5(Catalina)上触发相同内核崩溃的python代码。在两台Mac电脑上进行了测试,以确保这不是硬件问题:

https://github.com/ephes/django_async/blob/master/measure_threads_memory.py

也许我会去写一个bug报告。

汪辰阳
2023-03-14

Java建于90年代,当时只有多核处理器。

当然Java已经进化了,现代处理器也是如此。现在我们有8核处理器,具有大缓存(例如:12MB)。

尽管并发处理已经有了很大的发展,Java仍然是围绕单核处理器模型设计的。但是,随着历史的发展,让我非常简单地解释发生了什么。

仅仅通过在Java中创建一个新线程,我们就浪费了大量内存。

每个线程消耗约512KB-1MB,具体取决于您的JVM版本(请参阅一个线程在java和java线程中占用的内存:保留内存)。记住这一点,当不断创建新线程时,在某个时候它们将消耗堆的所有内存。

现在,我从未独自尝试过,但我假设您的计算机的操作系统由于“内存不足”错误而关闭/重新启动,作为一种对策。(这很像三重故障,导致Windows上臭名昭著的“蓝屏死亡”,机器需要重新启动以重置CPU的状态)

一个可能的解决方案是手动设置JVM使用的最大堆大小。因此,当您的程序完全使用预先分配的堆时,它不会导致关闭。请参考这个SO问题来了解如何做到这一点。

壤驷棋
2023-03-14

尽管控制台显示程序已完成,但JVM进程仍在运行,直到释放所有资源。同时,您的操作系统没有线程,速度慢且不稳定,这会导致所有进程都出现滞后,包括JVM终结。为了自卫,操作系统引发了内核恐慌。这就是MacOS重新启动的原因。

*OS-操作系统

 类似资料:
  • 在这个打印从1到10000000的所有数字、Haskell版本和C版本的简单程序中,为什么Haskell版本如此缓慢,以及哪些命令有助于学习如何提高Haskell程序的性能? 下面是一份报告,包含重现我激动人心的事件所需的所有细节,制作报告时会打印出来源,包括Makefile的来源:

  • 我需要帮助我的错误就像 代码:

  • 我正在学习多线程,想写一些与竞争条件的代码。然而,这些代码不起作用:我已经运行了很多次代码,但它总是打印10,这是正确的结果,没有竞争条件。有人能说出原因吗?谢了。 下面是主要函数。它将创建10个线程来修改一个静态变量,并在最后打印这个变量。 以下是Foo的定义:

  • 问题内容: 我知道不可能重新启动使用的Java Thread对象,但是我找不到 为什么 不允许这样做的解释。即使可以保证线程已完成(请参见下面的示例代码)。 我不明白为什么(至少是)方法不能以某种方式将Thread对象的内部状态重置为与刚创建Thread对象时相同的值。 示例代码: 问题答案: 我知道不可能重新启动使用的Java Thread对象,但是我找不到为什么不允许这样做的解释。即使可以保证

  • 我写了一个小基准来比较Python、Ruby、JavaScript和C的不同解释器/编译器的性能。正如预期的那样,结果表明(优化的)C打败了脚本语言,但是它的系数非常高。 结果是: 我想知道是否有人能解释为什么优化的C代码比其他代码快三个数量级以上。 C基准测试使用命令行参数以防止在编译时预计算结果。 下面,我放置了不同语言基准测试的源代码,它们应该在语义上是等价的。此外,我提供了优化的C编译器输

  • 问题内容: 想象一下以下课程: 我想重新启动线程以防万一。这不起作用。因为线程只能启动一次。第一个问题。为什么是这样? 据我所知,我必须重新创建的每个实例并调用以再次启动线程。如果是s,这不是很实际。我必须读取旧值的当前值,创建一个新值,并使用旧值在新对象中设置参数。第二个问题:这可以用更聪明,更轻松的方式完成吗? 问题答案: 之所以以这种方式实现threading.Thread,是为了保持线程对