0
  1. 如果我正确理解了每个 java 进程都与一个单独的 JVM 实例相关联,并且每个 JVM 实例都由操作系统提供一个堆内存,操作系统也会在 JVM 终止时重新收集该堆内存。So on termination even if there were some memory leaks all the memory will be reclaimed by the OS(Please correct if I have mistaken).
  2. 如果第 1 点是真的,为什么我们必须使用关闭挂钩。谷歌搜索后,主要建议释放所有资源并正常关闭。Even if it does not gracefully shutdown all the memory and resources would be freed?
  3. 我写了一个简单的关机钩子。在我的主线程中,我正在运行一个无限循环,然后使用中的终止按钮终止进程Eclipse。但是关闭钩子线程没有运行。Eclipse 中的终止进程是否会Runtime.getRuntime().halt(status)因为 AFAIK 突然终止 JVM 而未执行关闭挂钩而调用?
  4. 最后,如果我的主要代码如下 -

    public static void main(String args[]){
    Runtime.getRuntime().addShutdownHook(new Thread(new ShutDownHook()));
    System.out.println("Shutdown hook registered");
    System.out.println("Before calling exit");
    System.exit(0);
    System.out.println("After exit");       
    }
    

    为什么After exit不打印?当关闭钩子正在执行时,主线程必须继续进一步执行并打印After exit

4

1 回答 1

3

1)你是对的。

2) Java 进程的内存将被回收,但您可能需要进行其他清理,例如删除一些临时文件。

3)让我们去的javadocRuntime#addShutdownHook(Thread)

Java 虚拟机关闭以响应两种事件:

  • 程序正常退出,当最后一个非守护线程退出或调用 exit(等效于 System.exit)方法时,或

  • 虚拟机响应用户中断(例如键入 ^C)或系统范围的事件(例如用户注销或系统关闭)而终止。

您必须查看 Eclipse 的源代码,但 Eclipse 似乎终止了进程,而不是发送System.exit(..)或发送用户中断。这可能会越过 JVM,因此不会执行关闭挂钩。

4)您添加的关闭挂钩Runtime#addShutdownHook(Thread)被添加static IdentityHashMapApplicationShutdownHooks. 此类在如下所示Shutdown的初始化程序块中向该类注册其自己的关闭挂钩static

static {
    try {
        Shutdown.add(1 /* shutdown hook invocation order */,
            false /* not registered if shutdown in progress */,
            new Runnable() {
                public void run() {
                    runHooks();
                }
            }
        );
        hooks = new IdentityHashMap<>();
    } catch (IllegalStateException e) {
        // application shutdown hooks cannot be added if
        // shutdown is in progress.
        hooks = null;
    }
}

runHooks()方法是

static void runHooks() {
    Collection<Thread> threads;
    synchronized(ApplicationShutdownHooks.class) {
        threads = hooks.keySet();
        hooks = null;
    }

    for (Thread hook : threads) {
        hook.start();
    }
    for (Thread hook : threads) {
        try {
            hook.join();
        } catch (InterruptedException x) { }
    }
}

所以当前线程加入了所有其他线程。

什么时候

System.exit(0);

被调用,在某处Shutdown.sequence()被调用,调用Shutdown.hooks()实现为

private static void runHooks() {
    for (int i=0; i < MAX_SYSTEM_HOOKS; i++) {
        try {
            Runnable hook;
            synchronized (lock) {
                // acquire the lock to make sure the hook registered during
                // shutdown is visible here.
                currentRunningHook = i;
                hook = hooks[i];
            }
            if (hook != null) hook.run();
        } catch(Throwable t) {
            if (t instanceof ThreadDeath) {
                ThreadDeath td = (ThreadDeath)t;
                throw td;
            }
        }
    }
}

其中一个Runnable对象hooks就是我上面描述的。它不会产生新的Thread,它会与run().

一旦Shutdown.sequence()完成,系统就真的退出了,所以 finalSystem.out.println()不会执行。

于 2014-01-11T19:50:32.700 回答