你能在 Linux 中解释一下为什么一个打开了几个文件且长度不超过 200 行的文本编辑器会占用几 GB 的内存吗?
MEDIT(一个文本编辑器)占用 1.2GB 虚拟内存、50.8MB 常驻内存、22.4MB 共享内存和 84.6MB 磁盘写入操作。即使是 30MB 的文本文件,在我看来也是巨大的数量。
我的假设:
- 当您在 Linux 中打开应用程序时,内存统计会考虑所有其他中间过程,例如
mem
将数据写入磁盘、日志、日志等 。- 然后我建议,必须参考两个统计数据,1 个用于程序本身,一个用于共享操作。
- 内存统计数据与内存消耗密切相关,而不是实际
mem
统计数据——那么实际统计数据在哪里mem
? - 我不知道。
答案1
你能在 Linux 中解释一下为什么一个打开了几个文件且长度不超过 200 行的文本编辑器会占用几 GB 的内存吗?
MEDIT(一个文本编辑器)占用 1.2GB 虚拟内存、50.8MB 常驻内存、22.4MB 共享内存和 84.6MB 磁盘写入操作。即使是 30MB 的文本文件,在我看来也是巨大的数量。
听起来像是没有占用“一些 GB”的内存。它总共只占用 51 MB – 您应该查看“常驻”状态。
“虚拟内存”不是 RAM 使用量。(不要将其与 Windows 术语混淆,Windows 术语中同一个术语的含义完全不同——交换/页面文件使用量。)Linux 上的统计数据表示虚拟地址空间使用,并且地址空间可以映射到不一定在 RAM 中的各种东西:
程序使用的所有库都是内存映射的,这意味着即使它们没有加载到 RAM 中,它们也由地址范围表示然而;每当程序尝试访问该内存区域时,它们将按需逐页加载。
工作文件也可以进行内存映射,而不是使用传统的读/写/查找调用;这对于数据库文件尤其常见,但可以用于任何文件类型。同样,即使整个文件一次映射到虚拟内存中,它仍然只是按需加载到 RAM 中。
实际“驻留”的 RAM 被分配为大块(“区域”)中的匿名映射,这可能比当前使用的量大得多。例如,每个线程(GUI 应用程序将有线程)可能会预先获得自己的 128 MB 区域,即使它尚未请求任何内存分配。
(以前,Golang 或 Haskell 程序预先映射兆兆字节所有即将到来的内存分配的地址空间。)
一些软件(特别是 JavaScript 运行时)会映射大量地址空间作为“保护”(例如,参见 Webkit 的 Gigacage);映射保持完全为空并且不消耗任何 RAM。
虚拟地址空间独立于物理 RAM,并且每个进程都是分开的,因此即使程序的内存映射比 RAM 多,也不会出现任何问题。
即使是 MB,对于我来说,文本文件的数量也非常大。
它不是文本文件,而是程序本身及其使用的库。例如,仅“Pango”字体渲染库就有半兆字节(实际的国际字体很容易超过几兆字节);“GTK”小部件工具包有 8 MB,因为 libgtk-3.so 内置了所有资产(即复选框、滑块等的 SVG 和 PNG);等等。
(从技术上讲,程序可以在没有所有支持代码的情况下运行,但这不可避免地导致自制的“轻量级”工具包不支持除拉丁字符之外的任何内容,不知道“HiDPI”是什么,等等。)
使用pmap -x <pid>
(可能也有 GUI 工具)查看进程的虚拟内存分配,它将单独显示每个项目的“驻留”统计信息。
答案2
Linux 上的虚拟内存与 Windows 上的虚拟内存有很大不同。存在过度使用的情况,你可以看到基本上全部进程充分利用了这一事实。它们实际上请求了所有内存,但并未使用,这从其他内存值中可以看出。
Medit 也不是那么简单的编辑器:它似乎是基于 GTK 的,具有插件界面、文件系统浏览器和内置终端。
除非您在内存方面遇到特定问题,否则“解决方案”很简单:忽略虚拟内存大小列。
只有“简单”的应用程序(没有复杂的内存分配)才会有接近实际驻留内存大小的虚拟大小。较大的应用程序通常会以较大的块请求内存,以保持“实际”分配量较低,从而实现更好的系统整体性能和更少的内存碎片。
答案3
请注意,所有程序都被标记为使用大量虚拟内存,其数量接近或超过 1 GB。
虚拟内存代表进程的虚拟大小,即进程实际使用的内存总和。这包括进程映射到自身的内存(例如 X 服务器的显卡 RAM)、映射到其中的磁盘文件(最明显的是共享库)以及与其他进程共享的内存。
换句话说,虚拟内存表示程序能够访问的内存量,其中包括代码和数据。
我认为 MEDIT 使用的 1.2 GB 中最大的部分是由它使用的共享库组成的。诸如此类的库libc
非常庞大。但是,由于它们是共享的,因此尽管它们被计入使用它们的每个进程的虚拟内存中,但在实际物理内存中实际上只存在一个副本。
简而言之,这个虚拟内存大小确实是虚拟的,并没有太大的意义。