C语言中的exit(0)和Java中的System.exit(0)用法实践

6
在C语言中使用exit(0)并不是一个好的做法,如果有其他替代方案的话,因为它不会释放资源。但在Java中使用System.exit(0)呢?在这种情况下,能否信任垃圾回收器?
 exit(0);

Java:

 System.exit(0)

8
如果您即将结束应用程序,为什么还关心垃圾收集呢? - Sotirios Delimanolis
1
这是无关紧要的 - 你即将终止应用程序。这将释放所有内存。那么为什么要关心垃圾回收呢? - SevenBits
1
当您在Android中终止一个活动时,操作系统会处理内存管理,而不是由程序员来处理。 - foolmoron
2
在大多数操作系统中,您不必担心任何一种情况。但是,除了内存之外,还有其他资源需要担心:共享内存段、互斥量/信号量、套接字等。这些并不总是由C中的exit(0)处理,但我无法对Java发表意见。 - George
Android在这方面是一个相当不同的东西。您是否真正想了解Android应用程序如何处理此问题? - Michael Hampton
显示剩余3条评论
2个回答

2
当你在Java中调用System.exit时,垃圾收集器通常不会运行。然而,在我所知道的任何JVM中,都有其他东西可以回收分配的所有对象(通常在操作系统级别处理)。如果你依赖于对象终结器在JVM终止之前执行重要操作,则GC不运行只有重要意义。假设你的Java应用程序使用JNI等调用本地方法,那么这些方法可能访问可能有问题的系统资源。但是:
1. 通常情况下,操作系统确实会处理此类事情,至少对于现代Linux和UNIX版本来说是如此。
2. 垃圾收集器无论如何都不知道这些资源。如果操作系统无法回收它们,则Java垃圾收集器无法帮助。
如果您确实需要清理Java程序通过本地代码获取的这些资源,则最好的方法是在本地代码方法中实现清理,并使用“关闭挂钩”来运行它们。如果调用System.exit,则将运行关闭挂钩。
在JVM退出时将执行垃圾收集(如果之前调用了runFinalizersOnExit(true))。但是,这是一种已弃用的方法。Oracle网站这样解释它:因为它本质上是不安全的。如果在其他线程同时操作这些对象时,可能导致对活动对象调用终结器,从而导致不稳定的行为或死锁。虽然如果编写对象的类来“防御”此调用,则可以防止此问题,但大多数程序员不会防御它。他们认为在调用其终结器时,对象已经死亡。此外,该调用在“线程安全”方面并不“线程安全”,因为它设置了VM全局标志。这迫使每个具有终结器的类防御活动对象的终结!简而言之,这是一种危险的方法,它不会直接处理OP担心的资源类型。

一般来说,是的,但通常情况下,除非您特别努力清理它们,否则进程终止后System V IPC对象将保留。在我调试/修复程序时,当一个程序连续几次核心转储时,我曾经遇到过共享内存段上的Linux内核限制。消息队列和信号量也可能发生同样的情况。请参阅Linux上的ipcs和ipcrm手册页。 - George
1
当您在Java中调用System.exit时,垃圾回收器不会运行。但在Android中可能会有所不同。根据文档:如果之前已经使用true参数调用了runFinalizersOnExit(boolean)方法,则所有对象都将被正确地垃圾回收和完成最后操作(已加粗)。 - Ted Hopp
@TedHopp - 在Java SE中(至少),该方法已被弃用。然而,我已将该信息作为脚注添加。 - Stephen C

1
在C语言中,你需要将源代码编译成一个二进制文件,该文件只能按照逻辑编程和操作系统规则执行。然而,操作系统不会为你管理内存。它处理事件并向硬件发送信息告诉它如何运行,仅此而已。而在Java中,所有代码都被编译成Java自己的字节码。执行时它实际上并没有与操作系统通信。设计用于运行该字节码的虚拟机才是进行通信的工具。当你调用System.exit(0)时,你正在告诉虚拟机应用程序即将停止运行,从那里起,虚拟机将处理它自己的内存,其中包括你尚未通过垃圾回收器删除的任何东西,但前提是虚拟机也要退出。希望这有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接