代码之家  ›  专栏  ›  技术社区  ›  Jeff Meatball Yang

操作系统如何知道我的应用程序使用了多少内存?(为什么不收集垃圾?)

  •  5
  • Jeff Meatball Yang  · 技术社区  · 15 年前

    当我的任务管理器(top、ps、taskmgr.exe或finder)说某个进程正在使用xxx kb的内存时,它究竟在计算什么,以及如何更新它?

    就内存分配而言,用C++编写的应用程序是否与运行于虚拟机(如.NET或Java)的应用程序不同,与操作系统不同?

    最后,如果内存是透明的——为什么垃圾收集不是操作系统提供的功能或服务?


    事实证明,我真正感兴趣的是,为什么操作系统不能进行垃圾收集和碎片整理内存空间——我认为这是上面“简单”地”分配地址空间给进程的一个步骤。

    这些答案很有用!谢谢!

    3 回复  |  直到 15 年前
        1
  •  4
  •   Michael    15 年前

    这是一个大问题,我不希望在这里用一个答案来充分回答。我建议取一份 Windows Internals 它是一种宝贵的资源。 Eric Lippert 最近有一篇博客文章,很好地描述了如何查看操作系统分配的内存。

    一个进程正在使用的内存基本上只是 address space 由操作系统保留,可以由物理内存、页面文件或文件进行备份。无论是托管应用程序还是本机应用程序,这都是相同的。当进程退出时,操作系统会删除已分配给它的内存——虚拟地址空间只需删除,页面文件或物理内存备份可供其他进程使用。这是所有操作系统真正维护的——地址空间到某些物理资源的映射。映射可以随着进程需要更多内存或空闲而移动—物理内存内容可以移动到磁盘,操作系统也可以反过来移动以满足需求。

    根据这些工具,一个进程正在使用的实际上可能意味着以下几点之一:它可以是分配的总地址空间、分配的总内存(页面文件+物理内存)或一个进程实际使用的内存(驻留在内存中)。任务管理器对于这些可能性都有单独的列。

    操作系统不能进行垃圾收集,因为它无法洞察内存实际包含的内容——它只看到分配的内存页,看不到可能被引用或不被引用的对象。

    虽然操作系统的句柄是在虚拟地址级别分配的,但是在进程本身中,还有其他内存管理器,它们将这些大的、页面大小的块分割成一些对应用程序有用的块。Windows将返回以64K边界分配的内存,但堆管理器将其分成更小的块,供程序通过 new . 在.NET应用程序中,CLR将从垃圾收集堆中分发新对象,当该堆达到其限制时,将执行垃圾收集。

        2
  •  2
  •   JoshJordan    15 年前

    我不能回答你的问题,关于内存如何出现在C++与虚拟机等方面的差异,但我可以说,应用程序通常在初始化时使用一定的内存范围。然后,如果应用程序需要更多,它将从操作系统请求它,并且操作系统(通常)将授予它。这有许多实现——在一些操作系统中,其他应用程序的内存被移走,以便为您提供一个更大的连续块,而在其他系统中,您的应用程序获得不同的内存块。甚至可能涉及到一些虚拟内存处理。这一切都取决于抽象的实现。在任何情况下,内存仍然被视为程序中的连续内存——操作系统至少会处理这么多。

    对于垃圾收集,操作系统知道 界限 你的记忆,但不是你内心的东西。此外,即使它确实查看了应用程序使用的内存,它也不知道超出范围的变量使用了什么块,以及GC正在查找什么块。

        3
  •  2
  •   Paul Alexander    15 年前

    主要区别在于应用程序管理。微软将其区分为托管和非托管。当对象分配到内存中时,它们存储在特定的地址。对于托管和非托管应用程序都是如此。在托管世界中,“地址”被包装在对象句柄或“引用”中。

    当内存被VM垃圾收集时,它可以安全地挂起应用程序,在内存中移动对象,并更新所有“引用”以指向它们在内存中的新位置。

    在Win32样式的应用程序中,指针是指针。操作系统无法知道它是一个对象、一个任意的数据块、一个普通的32位值等,因此它无法对对象之间的指针进行任何推断,因此它无法在内存中移动它们或更新对象之间的指针。

    由于引用的处理方式,操作系统不能接管GC进程,而是由虚拟机来管理应用程序使用的内存。因此,虚拟机应用程序在操作系统中的表现完全相同。它们只需要请求内存块就可以使用,操作系统会将其提供给它们。当vm执行gc并压缩它的内存时,它可以将内存释放回操作系统供另一个应用程序使用。