我正在比较不同便携式浏览器的内存使用情况,但这个问题对于在任务管理器中在多个子进程中打开的所有程序来说都是普遍存在的。
参见 Sysinternals 的截图进程探索器以下:
例如,Firefox 仅在一个进程中打开,而 Google Chrome 则为每个选项卡启动多个进程。
那么如何才能获取一个程序打开的所有进程的总 RAM 使用量?(此处以 Google Chrome 为例。)
当然,我可以用计算器来算出总数……但一定有更方便的方法!
答案1
一般的答案是:不能,不准确。
假设您询问的是 RAM(物理内存)而不是虚拟内存 - Windows 为每个进程发布两个相关计数器,即总工作集和私有(对进程而言)工作集。(PerfMon 会向您显示这些。)任务管理器显示“私有”和“共享”(将它们加在一起就是总数)。进程资源管理器将它们显示为“工作集”(总数)、“WS 私有”、“WS 可共享”和“WS 共享”。ProcExp 会进行一些“深入挖掘”来找到后两者。
问题的关键在于“共享”,或者说总量的共享部分。
使用 Process Explorer 术语,“可共享”表示已分配给进程但至少可能与其他进程共享的 RAM。而“共享”表示实际被至少一个其他进程共享的 RAM 子集。
问题是您不知道有多少进程或哪些进程实际上在共享它。将所有“可共享”或“已共享”数字相加将得到比实际更大的总数,因为共享页面将计入恰好共享它们的所有进程中。并非每个进程,即使是运行相同程序(如 Chrome)的进程,也不一定都会在其总地址空间中共享相同的页面。
对于一组运行相同 .exe 的进程,例如 Chrome 的进程:通过将它们所有的“WS Private”计数器加在一起,然后将任何 Chrome 实例的“WS shareable”中最大的计数器添加到该总数中,您将得到一个最小数字......但实际数字可能更大。
Chrome 确实有 ge0rdi 提到的那个不错的自我报告功能。您需要的计数器是“内存”下的计数器。我机器上的 Chrome 与操作系统报告的内容并不完全一致,但对于所有实际用途来说已经足够接近了。
另一件需要考虑的事情是,虚拟内存操作系统中任何进程或进程子集的“内存使用情况”都极大地依赖于进程的行为和 RAM 压力。在 RAM 较多或较少的系统上运行它,或者在运行和需要 RAM 的其他程序较多或较少的系统上运行它,数字看起来会非常不同。因此,对于任何给定进程“需要”多少 RAM,并没有一个固定的数字。因此,即使“注意您的可用 RAM,然后关闭所有 Chrome 实例并查看可用 RAM 增加了多少”也不是一个好的测试。操作系统可能会将部分释放的 RAM 分配给其他进程,特别是当它们很忙的时候。
答案2
我不知道通常该怎么做,但是为了测量 Chrome 的总内存使用量,您可以写入about://memory
地址栏。
该Summary
部分显示所有 Chrome 进程的总内存使用情况。
答案3
不久前,我编写了一个很棒的(也许有点丑陋)批处理文件来实现这个功能,它需要 gnuwin32 的 sed 和 cut。
我写它是因为我对现代浏览器占用的 RAM 数量感到震惊并且想快速查看一下。
我目前正在尝试使它变得整洁,但它就是这样的。
因此,Chrome 占用了 3.4GB
C:\>ramchrome<ENTER>
>=1GB
3GB
3,480,288
3.4GB (rounded down)
3480288KB
这是批处理文件。以前它要简单得多。但我想添加 GB 和 KB 等单位,这占用了批处理文件的大部分空间。它非常具有前瞻性,因为即使 Chrome 占用了大量尧字节(尧字节是百万万亿兆字节),我的批处理也应该或至少是编写的,以支持这一点。
批处理文件内部工作原理很简单。它会创建一些临时文件。您可以查看这些文件。您会发现它基本上输出了所有进程的列表,过滤掉 chrome.exe 的进程,只抓取表明其使用了多少字节的部分。然后您可以输出最后一个临时文件,您会看到它只是每个 chrome.exe 进程使用的所有字节的列表,删除了所有逗号或空格,然后 for 语句将它们全部相加。最后一个临时文件可以在 excel 中打开。虽然没有必要。
您知道如何使用 bat 文件,只需运行它并查看其输出内容。您不需要知道它是如何工作的,但它就是这样工作的。您可以通过查看它生成的临时文件来了解。
@echo off
setlocal enableextensions enabledelayedexpansion
set tempfile1=%temp%\asdf1.a
set tempfile2=%temp%\asdf2.a
set tempfile3=%temp%\asdf3.a
set tempfile4=%temp%\asdf4.xls
tasklist >%tempfile1%
type %tempfile1% | grep "chrome" > %tempfile2%
cut -b 68- %tempfile2% > %tempfile3%
sed -r "s/\d32|K|,//g" %tempfile3% >%tempfile4%
set total=0
for /f %%f in (%tempfile4%) do @(set /a total+=%%f)>nul
:: --- added this
set a=%total%
if "%a:~-9,-6%"=="" echo ^< 1GB
if NOT "%a:~-13,-6%"=="" echo ^>=1GB
set yotta=%a:~-24,-21%
set zetta=%a:~-21,-18%
set exa=%a:~-18,-15%
set peta=%a:~-15,-12%
set tera=%a:~-12,-9%
set giga=%a:~-9,-6%
set mega=%a:~-6,-3%
set kilo=%a:~-3%
set prefix=
if NOT "!yotta!"=="" (
set yotta=!yotta!,
if "!prefix!"=="" (
set prefix=YB
echo !a:~-24,-21!!prefix!
)
)
if NOT "!zetta!"=="" (
set zetta=!zetta!,
if "!prefix!"=="" (
set prefix=ZB
echo !a:~-21,-18!!prefix!
)
)
if NOT "!exa!"=="" (
set exa=!exa!,
if "!prefix!"=="" (
set prefix=EB
echo !a:~-18,-15!!prefix!
)
)
if NOT "!peta!"=="" (
set peta=!peta!,
if "!prefix!"=="" (
set prefix=PB
echo !a:~-15,-12!!prefix!
)
)
if NOT "!tera!"=="" (
set tera=!tera!,
if "!prefix!"=="" (
set prefix=TB
echo !a:~-12,-9!!prefix!
)
)
if NOT "!giga!"=="" (
set giga=!giga!,
if "!prefix!"=="" (
set prefix=GB
echo !a:~-9,-6!!prefix!
)
)
if NOT "!mega!"=="" (
set mega=!mega!,
if "!prefix!"=="" (
set prefix=MB
echo !a:~-6,-3!!prefix!
)
)
if "!mega!"=="" (
if "!prefix!"=="" (
set prefix=KB
echo !kilo!
)
)
echo !yotta!!zetta!!exa!!peta!!tera!!giga!!mega!!kilo!
if "%prefix%"=="YB" echo !a:~-24,-21!.!a:~-21!YB (rounded down)
if "%prefix%"=="TB" echo !a:~-12,-9!.!a:~-9,1!TB (rounded down)
if "%prefix%"=="GB" echo !a:~-9,-6!.!a:~-6,1!GB (rounded down)
if "%prefix%"=="MB" echo !a:~-6,-3!.!a:~-3,1!MB (rounded down)
:: echo %a:~-13,-6%,%a:~-6,-3%,%a:~-3%
set a=
:: -----------
echo %total%KB
set tempfile1=
set tempfile2=
set tempfile3=
set tempfile4=
为了总结它的工作原理,下面是第一个临时文件 asdf1.a 的示例,您可以看到它列出了许多进程,而不仅仅是 chrome.exe
chrome.exe 5572 Console 1 64,784 K
chrome.exe 3880 Console 1 155,376 K
chrome.exe 14516 Console 1 106,932 K
chrome.exe 2524 Console 1 88,464 K
dllhost.exe 15996 Console 1 8,844 K
tasklist.exe 16232 Console 1 7,152 K
第二个临时文件更接近我们想要的,因为它过滤掉了 chrome.exe
asdf2.a
chrome.exe 5572 Console 1 64,784 K
chrome.exe 3880 Console 1 155,376 K
chrome.exe 14516 Console 1 106,932 K
chrome.exe 2524 Console 1 88,464 K
asdf3.a 越来越接近
64,784 K
155,376 K
106,932 K
88,464 K
asdf4.xml(不要问为什么它是.xls,也许我打算在 excel 中打开它)
64796
155592
114084
88464
因此,批处理文件已生成一个要求和的简单列表。
显然,批处理文件的这一行会进行求和
for /f %%f in (%tempfile4%) do @(set /a total+=%%f)>nul
笔记 使用批处理文件来编写这个程序很愚蠢。批处理文件通常不太便携,因为新版本的操作系统或新版本的命令对命令输出的轻微更改可能会导致程序无法运行。如果它依赖于存在不同版本的第三方程序,那就不好了。而且 gnuwin32 的许多命令都已过时,而 cygwin 的命令版本往往更为最新。这对我来说运行良好,但现在我尝试它时它给出了一个错误。
我可能会在某个时候用 C# 写一些东西。
还请注意,正如 Rick 指出的那样,这没有考虑程序使用的 DLL。虽然我个人认为对我有用的是了解可执行文件使用了多少(或者在某些现代浏览器的情况下,是可执行文件的许多实例!)