我正在阅读《Effective Java》。
在讨论finalize时,他说:
C++析构函数也用于回收其他非内存资源。在Java中,try-finally块通常用于此目的。
什么是非内存资源?
数据库连接是一种非内存资源吗?持有数据库连接的对象不也占用一些内存吗?
我正在阅读《Effective Java》。
在讨论finalize时,他说:
C++析构函数也用于回收其他非内存资源。在Java中,try-finally块通常用于此目的。
什么是非内存资源?
数据库连接是一种非内存资源吗?持有数据库连接的对象不也占用一些内存吗?
数据库连接、网络连接、文件句柄、互斥锁等需要在使用完毕后主动释放(不仅仅是进行垃圾回收)的资源。
是的,这些对象通常会占用一些内存,但关键点是它们还可以(可能是独占的)访问除内存之外的某些资源。
finalize()
方法来释放非内存资源,但问题在于这些终结器仅在对象被垃圾收集时运行。close()
,则几乎肯定会),则删除将失败,因为垃圾收集器极不可能在对象变得有资格进行垃圾收集并调用 delete()
之间的正好正确的点运行。另一个重要的部分是Java自动内存管理,它涉及到一些基本要素。
如果一个程序请求并分配资源,但从未释放这些资源以供其他用途使用,最终(通常很快)系统将耗尽这些资源。此时,系统要么停止运行,要么有时可以强制终止有问题的程序。
在90年代之前,资源管理(至少在主流开发中)是每个程序员都必须明确处理的问题。一些资源分配管理并不太难,主要是因为分配已经抽象化了(例如文件句柄或网络套接字),当不再需要时,可以获取资源、使用它并显式释放它。
然而,管理内存非常困难,特别是因为内存分配不能在设计时(在非平凡情况下)计算,而数据库连接可以通过这种方式进行可行的管理。(无法知道将使用多少内存,很难/不可能知道何时不再使用内存分配)。此外,内存分配往往会持续一段时间,而大多数其他资源分配仅限于狭窄的范围,通常在单个try块、方法或最多通常在类中。因此,供应商开发了抽象内存分配的方法,并将其纳入由执行环境而不是程序处理的单个管理系统中。
这是托管环境(例如Java,.NET)和非托管环境(例如通过操作系统直接运行的C、C++)之间的区别。在C/C++中,内存分配是显式完成的(使用malloc()/new和相关的重新分配),这会导致各种问题-我需要多少内存?如何计算何时需要更多/更少?如何释放内存?如何确保我没有使用已经释放的内存?如何检测和管理内存分配请求失败的情况?如何避免写入内存(也许不是我的内存)?所有这些都非常困难,会导致内存泄漏,核心转储和各种半随机、不可重现的错误。
因此,Java实现了自动内存管理。程序员只需分配一个新对象,既不关心,也不应该关心内存分配的内容或位置(这也是为什么托管环境中没有太多指针的原因)。
object thing = new Object();
这就是需要做的所有事情。JVM将跟踪可用的内存,当它需要分配内存时,它会释放不再使用的内存,并提供处理内存不足情况的方法,以尽可能地优雅地限制任何问题(并将问题限制在执行线程/ JVM而不是整个操作系统)。
自动内存管理现在是大多数编程的标准,因为内存管理是迄今为止最难管理的资源(主要是因为其他资源已经在某种程度上被抽象化了,例如数据库连接池、套接字抽象等)。
所以,来回答这个问题,是的,你需要管理所有资源,但在Java中,你不需要(也不能)显式地管理内存(尽管在某些情况下值得考虑,例如设计缓存)。这样留下了所有其他需要显式管理的资源(这些都是非内存资源,即除对象实例化/销毁之外的所有内容)。
所有这些其他资源都包装在内存资源中,但这里并不是问题所在。例如,你只能打开有限数量的数据库连接,只能创建有限数量的文件句柄。你需要管理这些的分配。使用finally块可以确保在出现异常时释放资源。
例如
public void server()
{
try
{
ServerSocket serverSocket = new ServerSocket(25);
}
catch (Exception exception)
{
// Something went wrong.
}
finally
{
// Clear up and deallocate the unmanaged resource serverSocket here.
// The close method will internally ensure that the network socket is actually flushed, closed and network resources released.
serverSocket.close();
// The memory used by serverSocket will be automatically released by the JVM runtime at this point, as the serverSocket has gone out-of-scope- it is never used again, so can safely be deallocated.
}
}