评估 C/C++ 内存泄漏时的虚拟与物理内存

virtual v. physical memory in assessing C/C++ memory leak

本文关键字:虚拟 物理内存 泄漏 C++ 内存 评估      更新时间:2023-10-16

我有一个C++应用程序,我正在尝试消除内存泄漏,我意识到我不完全了解虚拟内存和物理内存之间的区别。

top的结果(所以 16.8g = 虚拟,111m = 物理):

4406 um 20 0 16.8g 111m 4928 S 64.7 22.8 36:53.65 client

我的进程包含 500 个连接,每个用户一个,在这些数字上,这意味着每个用户大约有 30 MB 的虚拟开销。 在不详细介绍我的应用程序的情况下,如果我不知道虚拟内存的实际含义,那么将所有向量、结构、线程、堆栈上的函数等加在一起的唯一方法听起来很逼真。 没有 -O 优化标志,顺便说一句。

所以我的问题是:

  • C++中的哪些操作会使虚拟内存膨胀如此之大?
  • 如果我的任务正在使用虚拟内存的演出,这是有问题的吗?
  • 堆栈和堆函数变量、向量等 - 这些是否一定会增加物理内存的使用?
  • 删除内存泄漏(通过deletefree()等)是否一定会减少物理和虚拟内存的使用?

虚拟内存是程序处理的内容。它由mallocnew等返回的所有地址组成。每个进程都有自己的虚拟地址空间。虚拟地址的使用理论上受到程序地址大小的限制:32 位程序有 4GB 的地址空间;64位程序的功能远不止于此。实际上,进程可以分配的虚拟内存量小于这些限制。

物理内存是焊接到主板上或安装在内存插槽中的芯片。在任何给定时间使用的物理内存量仅限于计算机中的物理内存量。

虚拟

内存子系统将程序使用的虚拟地址映射到 CPU 发送到 RAM 芯片的物理地址。在任何特定时刻,您分配的大多数虚拟地址都是未映射的;因此,物理内存使用量低于虚拟内存使用量。如果访问已分配但未映射的虚拟地址,操作系统将无形地分配物理内存并将其映射。当您不访问虚拟地址时,操作系统可能会取消映射物理内存。

依次回答您的问题:

  • C++中的哪些操作会使虚拟内存膨胀如此之大?

newmalloc、大数组的静态分配。通常,程序中需要内存的任何内容。

  • 如果我的任务正在使用虚拟内存的演出,这是有问题的吗?

这取决于程序的使用模式。如果您分配了从未接触过的大量内存轨道,并且如果您的程序是 64 位程序,那么使用虚拟内存的演出可能是可以的。

此外,如果您的内存使用量无限增长,您最终会耗尽一些资源。

  • 堆栈和堆函数变量、向量等 - 这些是否一定会增加物理内存的使用?

不一定,但很可能。触摸变量的行为确保,至少暂时,它(以及"靠近"它的所有内存)都在物理内存中。(旁白:像std::vector这样的容器可以在堆栈或堆上分配,但包含的对象是在堆上分配的。

    删除内存
  • 泄漏(通过删除或free()等)是否一定会减少物理和虚拟内存的使用?

物理:可能。虚拟:是的。

虚拟内存是进程使用的地址空间。每个进程都有指针的 64 位(或 32 位,取决于体系结构)可寻址字节的完整视图,但并非每个字节都映射到真实的东西。操作系统管理将虚拟地址映射到实际物理内存页的表——或者该地址的真正含义(无论它似乎是应用程序的内存)。例如,对于您的应用程序,地址可能指向某个函数,但实际上它尚未从磁盘加载,当您调用它时,它会生成页面错误中断,内核通过从可执行文件加载适当的部分并将其映射到应用程序的地址空间来处理该中断, 所以它可以被执行。

从Linux的角度来看(我相信大多数现代操作系统):

  • 分配内存会膨胀虚拟内存。实际上,使用分配的内存会增加物理内存使用量。做得太多,它将被交换到磁盘,最终你的进程将被杀死。
  • mmap文件只会增加虚拟内存使用量,这包括可执行文件的大小:它们越大,使用的虚拟内存就越多。
  • 用尽虚拟内存的唯一问题是它可能已耗尽。这主要是 32 位系统上的问题,您只有 4gb(并且为内核保留了 1gb,因此应用程序数据只有 3gb)。
  • 在堆栈上分配变量的函数调用可能会增加物理内存使用量,但您(通常)不会泄漏此内存。
  • 分配的堆变量会占用虚拟内存,但只有在读取/写入它们时才会实际获取物理内存。
  • 释放或删除变量不一定会减少虚拟/物理内存消耗,它取决于分配器内部,但通常会减少

您可以设置以下环境变量来控制 malloc 的内部内存分配。设置后,它将回答所有四个问题。如果您想了解其他选项,请参阅:

http://man7.org/linux/man-pages/man3/mallopt.3.html

导出 MALLOC_MMAP_THRESHOLD_=8192

导出MALLOC_ARENA_MAX=4