什么是非内存资源?

时间:2011-08-12 08:48:20

标签: java effective-java

我正在阅读“Effective Java”。

在关于敲定的讨论中,他说

  

C ++析构函数也用于回收其他非内存资源。   在Java中,try finally块通常用于此目的。

什么是非内存资源?

数据库连接是非内存资源吗?持有数据库连接的对象是否占用了一些内存?

4 个答案:

答案 0 :(得分:22)

数据库连接,网络连接,文件句柄,互斥体等。完成后需要释放的东西(不仅仅是垃圾收集)。

是的,这些对象通常会占用一些内存,但关键的一点是除了内存外,它们还可以(可能是排他地)访问某些资源

答案 1 :(得分:5)

  

数据库连接是非内存资源吗?

是的,这是最常见的例子之一。其他是文件句柄,本机GUI对象(例如Swing或AWT窗口)和套接字。

  

用于保存数据库连接的Object是否占用了一些内存?

是的,但重点是资源的非内存部分也需要释放,并且通常比对象使用的相对较少的内存量更少。通常,此类对象具有释放非内存资源的finalize()方法,但问题是此终结器仅在对象被垃圾回收时运行。

由于对象很小,可能有大量可用的堆内存,因此垃圾收集器很少运行。在垃圾收集器的两次运行之间,非内存资源不会被释放,你可能会耗尽它们。

这甚至可能导致只有一个对象出现问题:例如,如果要通过打开文件系统,打开目标文件,复制数据然后删除原始文件来在文件系统之间移动文件,则删除将失败,如果该文件仍然打开 - 几乎可以肯定的是,如果您只将输入流的引用设置为null并且不显式调用close(),因为垃圾收集器不太可能完全运行对象符合垃圾收集条件和调用delete()

之间的正确点

答案 2 :(得分:0)

另一个重要的和平 Java Automatic Memory Management涉及一些必需品。

答案 3 :(得分:-1)

在我看来,问题更好地回答了问题 - '为什么我不需要手动释放内存'。

这提出了一个问题,'为什么我需要释放任何资源?'

从根本上说,您运行的程序使用多种形式的资源来执行和工作(CPU周期,内存位置,磁盘访问等)。几乎所有这些都受到“稀缺”的影响,也就是说,任何此类资源都有固定的可用池,如果所有资源都已分配,那么操作系统无法满足请求,而且一般来说,您的程序无法继续并且非常不合理地死亡 - 可能使整个系统不稳定。我想到的唯一一个并不稀缺的是CPU周期,您可以根据需要发布尽可能多的这些,您只能受到发布它们的速率的限制,它们不会被同时使用感觉内存或文件句柄。

因此,您使用的任何资源(内存,文件句柄,数据库连接,网络套接字等)都来自固定数量的此类资源(避免使用“池”一词)以及您的程序(以及承保) -mind其他程序,更不用说操作系统本身)分配这些资源,可用量减少。

如果一个程序请求并分配资源并且永远不会释放它们以便在其他地方使用,最终(通常很快)系统将耗尽这些资源。此时,系统停止,或者有时可能会突然杀死违规程序。

90年代以前,资源管理(至少在主流开发中)是每个程序员必须明确处理的问题。一些资源分配管理并不太难,主要是因为分配已经被抽象(例如文件句柄或网络套接字),并且可以获取资源,使用它并在不再需要时显式释放它。

然而,管理内存非常困难,特别是因为内存分配不能(在非平凡的情况下)在设计时计算,而数据库连接可以通过这种方式进行管理。 (没有办法知道你将使用多少内存,很难/不可能知道何时不再使用内存分配)。此外,内存分配倾向于暂停一段时间,其中大多数其他资源分配限于窄范围,通常在单个try-block或方法中,通常在一个类中。因此,供应商开发了抽象内存分配并将其置于单个管理系统下的方法,由执行环境而不是程序处理。

这是托管环境(例如Java,.NET)和非托管环境(例如直接通过OS运行的C,C ++)之间的差异。在C / C ++中,内存分配是显式完成的(使用malloc()/ new和相关的重新分配),这会导致各种问题 - 我需要多少?我如何计算何时需要更多/更少?我该如何释放内存?我如何确保我没有使用已经发布的内存?如何检测和管理内存分配请求失败的情况?如何避免写入内存(甚至可能不是我自己的内存)?所有这些都非常困难,导致内存泄漏,核心转储以及各种半随机,不可再现的错误。

因此,Java实现了自动内存管理。程序员只是简单地分配一个新的对象,既不感兴趣,也不应该根据内存的分配内容(这也是托管环境中指针的方式不多的原因):

object thing = new Object();

这就是所有需要做的事情。 JVM将跟踪可用内存,何时需要分配,何时可以释放(因为它不再使用),提供尽可能优雅地处理内存不足情况的方法(并将任何问题限制在执行线程/ JVM而不是关闭整个操作系统。)

自动内存管理现在是大多数编程的标准,因为内存管理是迄今为止最难管理的资源(主要是因为其他资源已在某种程度上被抽象出来,数据库连接池,套接字抽象等)。

所以,回答这个问题,是的,你需要管理所有资源,但是在Java中你不需要(也不能)自己明确地管理内存(虽然在某些情况下值得考虑,例如设计一个高速缓存)。这会留下您需要显式管理的所有其他资源(这些是非内存资源,即除了对象实例化/销毁之外的所有内容)。

显然,所有这些其他资源都包含在内存资源中,但这不是问题所在。例如,您可以打开有限数量的数据库连接,可以创建有限数量的文件句柄。您需要管理这些的分配。使用finally块可以确保资源被释放,即使发生异常也是如此。

e.g。

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.
  }
}