c++ - 在 Linux 上与静态 C 运行时链接的共享库和可执行文件。他们每个人都像Windows一样有单独的堆吗?

标签 c++ c linux memory-management crt

我很清楚 Window 堆分配和堆堆栈等。虽然我是 Linux 的新手,但我不太清楚它是如何工作的?

在 Windows 上:

  1. 在进程开始时,操作系统会创建一个名为“进程堆”的默认堆。如果没有使用其他堆,则进程堆用于分配 block 。
  2. 语言运行时也可以在进程中创建单独的堆。 (例如,C 运行时会创建自己的堆。)
  3. 除了这些专用堆之外,应用程序或许多加载的动态链接库 (DLL) 之一可能会创建和使用单独的堆,称为私有(private)堆
  4. 这些堆位于所有虚拟内存系统中操作系统的虚拟内存管理器之上。
  5. a) C/C++ 运行时 (CRT) 分配器:提供 malloc() 和 free() 以及新建和删除运算符。 b) 作为其初始化的一部分,CRT 为其所有分配创建了这样一个额外的堆(此 CRT 堆的句柄在 CRT 库内部存储在一个名为 _crtheap 的全局变量中)。 c) CRT 创建自己的私有(private)堆,它位于 Windows 堆的顶部。 d) Windows 堆是围绕 Windows 运行时分配器 (NTDLL) 的薄层。 e) Windows 运行时分配器与虚拟内存分配器交互,虚拟内存分配器保留并提交操作系统使用的页面。

我们的 DLL 和 exe 链接到多线程静态 CRT 库。我们创建的每个 DLL 和 exe 都有自己的堆,即 _crtheap。分配和取消分配必须从各自的堆中发生。从 DLL 动态分配的,不能从可执行文件中取消分配,反之亦然。

使用/MD 或/MDd 在 DLL 和 exe 中编译我们的代码以使用运行时库的多线程特定和 DLL 特定版本,会将 DLL 和 exe 链接到同一个 C 运行时库,因此链接到一个_crtheap。分配总是与单个模块中的取消分配配对。

这在 Liunx 上是否相同? 那里有什么堆? CRT 堆呢?

最佳答案

我真的不知道如何回答这个问题,但我会尝试提供足够的一般信息,以便我能找到您需要知道的内容。

作为一个 unix 人,我从你的问题中了解到 Windows 内存管理是你们经常使用“堆”这个词。我们不这样做,除非作为“由 malloc 管理的内存区域”的非正式同义词。

有 2 个主要的动态内存分配原语需要注意:brkmmap。包括 malloc 在内的所有其他分配函数都建立在这些函数之上。

brk 是旧的。它的工作原理是在 bss 段结束后简单地向进程的虚拟内存映射添加更多内存。您向 brk 传递一个值,该值将成为进程的“中断”地址 - 分配的虚拟内存的末尾。

malloc 可以构建在 brk 之上,每次需要更多内存时都用一个新的、更高的值调用它,并维护一些内部数据结构来跟踪已释放的内容和仍在使用的内容使用。 (在经典实现中没有在空闲时将内存返回给系统。)某些 malloc 实现的内部数据结构必须是 heap。给 brk 段起绰号:“堆”。

另请参阅:What does brk( ) system call do? (它有图片!)

程序直接调用brk确实很不寻常。 (甚至是薄包装器 sbrk)。在普通程序中每次使用 brk 都是通过 malloc。请记住,尽管您将 C 库(包括 malloc)视为某种可选的额外功能,但我们有一个与 C 紧密耦合的操作系统,因此不使用 libc 的程序用于低像内存管理这样的级别的东西确实很奇怪。所以大多数时候,brk 段中的所有内存 a.k.a.“堆”都由 malloc 管理。然而,反之则不然,因为......

mmap,比 brk 更新(mmap 是 90 年代的;brk 是 70 年代的)提供了很多选项。当您想要将一个文件映射到内存中,或者分配几个不连续的内存块而不是仅仅在原始数据 block 的末尾添加一些空间时,您可以使用 mmap。共享库加载器使用 mmap 映射每个库的文本和数据。现代 malloc 实现对大请求使用 mmap,对小请求使用 brk。我们还有 mremap,它将映射重定位到新的虚拟地址,同时将其保持在相同的物理地址,从而允许 realloc 避免昂贵的拷贝。

如果您查看 Linux 上的 /proc/$PID/maps,您会看到一个标记为 [heap] 的内存区域。那是 brk 段。每个进程只有其中一个。 (我见过一些示例,其中 maps 文件显示了其中的 2 个,但它们是连续的并且具有相同的属性,因此实际上相当于一个区域。我不知道是什么原因导致双重列表.)

考虑到所有这些背景,分配“额外堆”意味着什么?您可以使用 mmap 从系统请求一些内存,从而为您提供一个独立于 malloc 的区域。然后,您可以对该区域进行自己的类似 malloc 的管理,将其分成不同大小的 block 并跟踪未使用的部分。但是你的新分配器不会是“堆”。这实际上没有任何意义,因为系统对堆一无所知。

关于c++ - 在 Linux 上与静态 C 运行时链接的共享库和可执行文件。他们每个人都像Windows一样有单独的堆吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22859335/

相关文章:

c++ - 从类中运行线程

linux - Linux 中使用 readdir() 的 Level 2 I/O 可能吗?

c - 在C中使用数组进行BCD转换

c - Linux 上的 "Alarm clock"消息

linux - 为什么我的测量显示进程消耗的 CPU 时间比可用时间多?

c++ - 如何像普通 C 函数一样使用正确的 'this' 指针调用 C++ 类成员函数? (指向类成员函数的指针)

c++ - GDB 看不到源代码

c++ - 不错的简短且可免费下载的 STL 教程

c - fedora 22 链接共享对象时出现多个 undefined reference 错误

c - MIPS 反转位代码(从 C 代码转换)......但它不起作用