【发布时间】:2011-09-25 16:46:58
【问题描述】:
内存分配是系统调用吗?例如,malloc 和 new。是由不同进程共享并由操作系统管理的堆。私有堆呢?如果堆中的内存分配由操作系统管理,这有多贵?
我还希望有一些链接可以指向可以阅读有关此主题的更多信息。
【问题讨论】:
标签: c++ c operating-system heap-memory
内存分配是系统调用吗?例如,malloc 和 new。是由不同进程共享并由操作系统管理的堆。私有堆呢?如果堆中的内存分配由操作系统管理,这有多贵?
我还希望有一些链接可以指向可以阅读有关此主题的更多信息。
【问题讨论】:
标签: c++ c operating-system heap-memory
一般来说,malloc 和 new 不会在每次调用时执行系统调用。但是,它们使用较低级别的机制来分配大内存页。在 Windows 上,较低的机制是 VirtualAlloc()。我相信在 POSIX 系统上,这在某种程度上等同于 mmap()。这两者都执行系统调用以在操作系统级别为进程分配内存。后续分配将使用这些大页面的较小部分,而不会引发系统调用。
堆通常是内部进程并且不在进程之间共享。如果你需要这个,大多数操作系统都有一个用于分配shared memory 的 API。 Boost.Interprocess 库中提供了这些 API 的可移植包装器。
如果你想了解更多关于内存分配和与操作系统的关系,你应该看看一本关于操作系统的好书。我总是推荐 Andrew S. Tanenbaum 的 Modern Operating Systems,因为它很容易阅读。
【讨论】:
brk(2) 和 sbrk(2) 与 mmap(2) 一起使用。我还要提到 Knuth 的 AOCP Vol。我也是内存分配的一个很好的参考。
syscall 或sysenter 指令的东西。这些说明在ntdll.dll,而不是kernel32.dll。它们位于名称以Nt 和Zw 开头的函数内部,而不是Rtl。事实上,HeapAlloc 调用了RtlAllocateHeap,这不一定必须执行任何系统调用。
(假设操作系统具有内存保护。在嵌入式设备中可能并非如此。)
内存分配是系统调用吗?
不一定每次分配。如果进程的堆已经不足以满足所请求的分配,则该进程需要调用内核,但 C 库通常会在这样做时请求更大的块,以减少系统调用的次数。
是由不同进程共享并由操作系统管理的堆。私有堆呢?
堆不在进程之间共享。但它在线程之间共享。
内核内存分配系统调用的昂贵程度完全取决于操作系统。由于这是很常见的事情,您可以期望它在正常情况下是有效的。在内存不足的情况下事情会变得复杂。
【讨论】:
参见 Win32 中的分层内存管理。
内存分配始终是系统调用,但分配是作为页面进行的。如果提交的页面中有可用空间,内存管理器将分配请求的空间而不改变内核模式。 HeapAlloc 最好的一点是,它提供了对分配的精细控制,其中 Virtual Alloc 围绕单个页面的分配。这可能会导致内存使用过多。
基本上,默认堆和私有堆的处理方式相同,只是在链接期间指定了默认堆大小。默认堆大小为 1 MB,并根据需要增长。
【讨论】:
"Memory allocation is always a system call" 这意味着每次调用malloc() 都会导致系统调用(转换到内核模式),这是 100% 不正确的。
内存分配函数和诸如 malloc/free 和 new/delete 之类的语言语句不是系统调用。 Malloc\free 是 C\C++ 库的一部分,new\delete 是 C++ 运行时系统的一部分。两者的调用有时会导致系统调用。在其他语言中,内存分配以类似的方式实现。
一般来说,内存管理是完全不涉及操作系统的,因为内存是主要的系统资源之一,并且由于操作系统内核进行了这种全局内存管理。但是由于系统调用相对昂贵的事实,人们试图以这样一种方式来设计语言和内存分配库,以尽量减少系统调用的数量。
据我所知,堆是一个进程内实体。这意味着所有内存分配/释放请求完全由进程本身管理。操作系统只知道堆的位置和大小,并为来自进程内内存管理系统的两种类型的请求提供服务:
add memory page at virtual address X
release memory page from virtual address X
本地内存管理系统在判断堆内存池内存不足和堆内存池内存过多时请求这些服务。 尽管内存分配通常以最小化系统调用量的方式设计,但它仍然保持比堆栈上的内存分配更昂贵的顺序。这是因为堆的内存分配\释放算法比栈的复杂和昂贵。
【讨论】: