3

作为一名 C 和 C++ 程序员,我使用mallocnew分配内存。我只是想知道:操作系统如何分配内存?

  1. 它是从 RAM 分配,还是从硬盘分配,还是从其他地方分配?

  2. 我可以从硬盘借内存以防万一吗?

4

4 回答 4

13

它实际上比你想象的要复杂得多。操作系统在“页面”中考虑所有内容,它将 RAM 分成页面,将硬盘驱动器分成页面。当您的程序启动时,它会检查您的可执行文件占用了多少内存,为其选择一些 RAM 页面,并将这些页面分配给您的程序。如果 RAM 中没有“可用”页面,则它会占用 RAM 中较旧的一些页面,并将它们保存到隐藏的硬盘驱动器中,然后将这些页面提供给您。

当您在程序中分配内存时,程序的内存管理器将尝试在操作系统分配给它的页面中找到空闲位置。如果不够,它会向操作系统请求更多页面,操作系统会腾出更多空间并为您的应用程序提供更多页面。

如果您的程序有一段时间没有使用过的页面(有时甚至是代码),操作系统可能会将该页面保存到硬盘驱动器中,当您的程序再次尝试使用该页面时,操作系统会暂停您的程序,将页面重新加载到 RAM 中,然后恢复您的程序。

这是一个没有意义的图表

C++ addresses           RAM         hard drive
+------------+    +------------+  +------------+  
| 0x00010000 |\ ->| 0x00010000 |  | 0x00010000 | 
+------------+ X  +------------+  +------------+
| 0x00020000 |/ ->| 0x00020000 |  | 0x00020000 |
+------------+    +------------+  +------------+
| 0x00030000 |-->?         /----->| 0x00030000 |
+------------+            /       +------------+
| 0x00040000 |-----------/        | 0x00040000 |
+------------+
|    etc     |

因此,在这段代码中,您的代码的堆栈内存为 0x00010000-0x0002FFFF,并且您分配了一些动态内存,位于 0x0004000 中。据你所知!实际上,当您访问 0x0002000 时,操作系统会说“哦,我已将您的页面存储在 RAM 地址 0x00010000 中”并为您读取这些值。您有一段时间没有接触 0x00040000 的页面,因此操作系统将其保存到硬盘驱动器位置 0x00030000 的硬盘驱动器中,但如果您尝试使用它会将其放入 RAM 中。操作系统还没有给你地址0x00030000,所以如果你尝试使用它,操作系统会告诉你这个地址没有任何实际的页面,你会得到一个分段错误(segfault)。有趣的是,当您要求一个大的连续块(​​如向量)时,操作系统可以为您提供它发现的任何旧页面,不必担心它们是否连续。它们看起来与您的程序相邻,这很重要。

这也允许操作系统对另一个程序隐藏一个程序的内存,从而使它们无法读取或修改其他程序的内存空间。他们很安全!除了...有一些方法可以告诉操作系统在两个程序之间共享一个页面(尽管它们在每个程序中可能有不同的地址),从而允许它们共享页面。DLL 执行此操作。

实际上,它远比这复杂。

于 2013-09-04T22:26:02.310 回答
5

1)它是从 RAM 分配还是从硬盘分配,还是从其他地方分配?

在支持虚拟内存的现代系统/平台上,操作系统决定在哪里以及如何分配/存储内存。该系统还可以自由地将内存从一个地方移动到另一个地方,无论是在内存上还是在磁盘上。

2)我可以借用硬盘的内存以防万一吗?

管理内存的操作系统可以从磁盘借用内存。

您还可以通过将数据存储在文件中来显式地从磁盘借用内存。C 和 C++ 标准库 (stdio.hfstream) 支持文件操作。

于 2013-09-04T22:17:58.260 回答
1

当您寻址由mallocor 运算符分配的内存时new,它位于 RAM 中并且具有唯一的地址。操作系统的工作是在寻址时将该内存块放在 RAM 中,但它可能会自行决定将其交换到磁盘上。由于交换速度很慢,因此由操作系统决定如何最小化交换。

使用“虚拟内存”的操作系统允许您设置有多少磁盘空间可供虚拟内存管理器使用。

尽管您可能会考虑使用数据库来管理数据是否更好,但您无需尝试自己进行管理,尤其是在数据的生命周期比单个会话长的情况下。

于 2013-09-04T22:09:22.183 回答
1

这个答案将以 Linux 为中心

它比看起来要复杂得多。当您分配一块内存时,可能会发生以下两种情况之一。如果您的进程已经有足够的内存先前已释放但未返回给操作系统(分配器通常不会),则该内存将在分配器表中标记为已分配,并将返回。当进程还没有内存时,分配器会向操作系统询问更多。在 Linux 上,这意味着brkorsbrk系统调用。我不知道这在 Windows 或 OSX 上意味着什么。

所有现代的通用操作系统(Linux、Windows、OSX 及其衍生产品)都使用虚拟内存,地址的概念不一定指向真实的 RAM。在你把东西放进去之前,你分配的内存可能根本不存在。一旦开始使用它,操作系统就需要在 RAM 中为它腾出空间。为此,操作系统会将其他未使用的页面(部分内存)存储在磁盘上的交换文件或分区中(如果已配置)。

操作系统不断在交换存储和实际 RAM 之间进出内存页。每当您的进程访问当前不在 RAM 中的内存部分时,处理器会生成页面错误,这会导致操作系统从磁盘加载该页面,并通过移动其他页面为它们腾出内存空间进入交换。


因此,基本上,在现代操作系统中,内存可以来自操作系统选择的任何地方,并且在您分配它时甚至可能不存在


注意:一些操作系统,比如大多数时候的 Linux,甚至会让你分配它不需要给你的内存。这称为过度使用内存。

于 2013-09-04T22:20:28.540 回答