作为C和C ++程序员,我使用malloc
和new
来分配内存。我只是想知道:操作系统如何分配内存?
它是从RAM还是从硬盘或其他地方分配的?
为了以防万一,我可以从硬盘借内存吗?
答案 0 :(得分:12)
实际上比你想象的要复杂得多。操作系统会考虑“页面”中的所有内容,将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就是这样做的。
实际上,它远比这复杂得多。
答案 1 :(得分:5)
1)它是从RAM还是从硬盘或某个地方分配的 别的?
在支持虚拟内存的现代系统/平台上,操作系统决定在何处以及如何分配/存储内存。系统也可以自由地将内存从一个地方移动到另一个地方,无论是在ram还是在磁盘上。
2)为了以防万一,我可以从硬盘上借内存吗?
管理内存的操作系统可以从磁盘借用内存。
您还可以通过将数据存储在文件中来明确地从磁盘中借用内存。 C和C ++标准库(stdio.h
和fstream
)启用文件操作。
答案 2 :(得分:1)
当您处理由malloc
或运营商new
分配的内存时,它位于RAM中并具有唯一的地址。操作系统的工作是在寻址时在RAM中使用该块内存,但它可以自行决定将其交换到磁盘。由于交换速度很慢,因此要由操作系统确定如何最小化交换。
使用“虚拟内存”的操作系统允许您设置虚拟内存管理器可用的磁盘空间大小。
尽管您可能会考虑使用数据库来管理数据是否更好,尤其是在数据的生命周期长于单个会话时,您无需尝试自行管理。
答案 3 :(得分:1)
这个答案将以Linux为中心
它看起来要复杂得多。分配内存块时,可能会发生以下两种情况之一。如果您的进程已经有足够的内存以前已释放但未返回到操作系统(分配器通常不会),则该内存将在分配器表中标记为已分配,并将返回。当进程还没有内存时,分配器会向操作系统询问更多内存。在Linux上,这意味着brk
或sbrk
系统调用。我不知道它在Windows或OSX上意味着什么。
所有现代的常见操作系统(Linux,Windows,OSX及其衍生产品)都使用虚拟内存,地址的概念不一定指向真正的内存。在你输入内容之前,你分配的内存可能根本不存在。一旦开始使用它,操作系统需要在RAM中为它腾出空间。为此,操作系统会将其他未使用的页面(部分内存)存储在磁盘上的交换文件或分区中(如果已配置)。
操作系统不断地在交换存储和实际RAM之间移入和移出内存页。每当您的进程访问当前不在RAM中的内存部分时,处理器会生成页面错误,导致操作系统从磁盘加载该页面,并通过移动其他页面为内存腾出空间交换。
所以基本上,在现代操作系统中,内存可以来自操作系统选择的任何地方,当你分配它时可能不存在。
注意:有些操作系统,比如Linux,大多数情况下,甚至会让你分配它没有给你的内存。这称为过度使用内存。