You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows进程实际内存占用疑问:为何1GB分配内存工作集仅占约80%

Windows 10内存分配与工作集机制解析

平台特性

  • CPU:Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz 1.80 GHz
  • 内存:8GB
  • 环境:Windows 10、Visual Studio、MSVC 编译器

我用C++编写了一段内存分配与读写代码,通过.NET的System.Diagnostics.Process类监控进程的内存统计信息,代码如下:

#include <iostream>
#include <chrono>
#include <thread>

int main()
{
   long long n = 1'000'000'000;
   std::cout << "part 1 started" << std::endl;
   char* arr = static_cast<char*>(malloc(n));
   std::this_thread::sleep_for(std::chrono::milliseconds(500));
   arr[n - 1] = rand();
   std::this_thread::sleep_for(std::chrono::milliseconds(500));
   std::cout << "part2 started" << std::endl;
   for (long long i = n / 5.0 * 4.0; i < n; i++)
      arr[i] = rand();
   std::this_thread::sleep_for(std::chrono::milliseconds(500));
   std::cout << "part3 started" << std::endl;
   for (long long i = n/5; i < n; i++)
      arr[i] = rand();
   std::this_thread::sleep_for(std::chrono::milliseconds(500));
   long long tmpll = 0;
   for (int i = 0; i < 100000000; i++)
   {
      tmpll = 0;
      if (rand() % 2)
         tmpll = 2'400'000'000;
      if (rand() % 2)
         tmpll += 2'400'000'000;
      if (rand() % 2)
         tmpll = 2'400'000'000;
      tmpll += rand();
      tmpll += rand();
      if (tmpll < 0) tmpll = abs(tmpll);
      tmpll %= n;
      arr[tmpll] = rand();
   }
   std::cout << arr[rand() % n] << std::endl;
   std::this_thread::sleep_for(std::chrono::milliseconds(2000));
   std::cout << "ended" << std::endl;
   free(arr);
   std::cout << "freed" << std::endl;
}

观察到的现象

监控PrivateMemorySize64、WorkingSet64和PeakWorkingSet64后发现:

  • PrivateMemorySize64与申请的1GB内存量一致,但PeakWorkingSet64始终小于该值(通常不超过分配空间的80%)。
  • 禁用交换文件并重启后,依然得到类似结果:
PrivateMemorySize64 = 1002602496
WorkingSet64 = 803287040
PeakWorkingSet64 = 803291136
  • 重新启用交换文件后,结果无明显变化:
PrivateMemorySize64 = 1002516480
WorkingSet64 = 803246080
PeakWorkingSet64 = 803299328

我原以为随机写入数组各个位置会迫使系统为全部1GB内存分配物理存储,但工作集峰值始终达不到1GB,需要解释Windows 10在此场景下的实际机制。


核心机制解析

  1. 虚拟内存的延迟分配
    Windows采用请求分页机制:malloc仅在进程的虚拟地址空间中预留1GB连续地址范围,不会立刻分配对应物理内存。只有当程序实际读写某页内存时,系统才会触发页错误,为该页分配物理内存。

  2. 代码中的未访问页面
    你的代码从未触及数组的前n/5区域(即200MB):

  • part2写入了数组的后1/5区域,part3写入了后4/5区域,后续随机写入也不会覆盖前1/5的所有页面。
  • 工作集(Working Set)统计的是进程实际占用的物理内存页面,未被访问的虚拟页不会占用物理内存,自然不会计入WorkingSet或PeakWorkingSet。
  1. 禁用交换文件的影响
    禁用交换文件仅限制了系统将物理页换出到磁盘的能力,但延迟分配机制依然生效。未被访问的虚拟页不需要物理内存,所以即使没有交换文件,这部分内存也不会被分配,工作集自然无法达到1GB。

  2. PrivateMemorySize64的定义
    PrivateMemorySize64统计的是进程已提交的虚拟内存总量(即通过malloc等调用向系统承诺使用的内存),不管是否实际分配了物理内存,这就是它与工作集数值差异的核心原因。

验证方法

若要让PeakWorkingSet达到1GB,只需在代码中遍历整个数组并写入每个位置:

// 在free(arr)前添加
for (long long i = 0; i < n; i++) {
    arr[i] = 0; // 触发所有页的物理内存分配
}

此时再观察PeakWorkingSet64,数值会接近1GB。

内容的提问来源于stack exchange,提问作者vev01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:25:16