未托管内存未在任务管理器显示的原因及测试方法咨询
为什么任务管理器看不到
Marshal.AllocHGlobal分配的100MB内存? 这其实是Windows虚拟内存系统的懒加载(lazy commitment)机制在起作用。当你调用Marshal.AllocHGlobal(100000000)时,操作系统只是为你的进程预留了100MB的虚拟地址空间,但并没有真正将物理内存(或页面文件中的空间)分配给它。只有当你实际写入或读取这块内存中的内容时,Windows才会触发“提交”操作,把真正的内存页分配给进程,这时候任务管理器里的内存占用才会体现出来。
你的代码里只是分配了地址空间,没有对这块内存做任何读写操作,所以任务管理器显示的是进程当前实际提交的内存,自然看不到这100MB的变化。
测试非托管堆内存消耗的方法
如果想验证非托管内存的分配情况,你可以试试这些方法:
1. 触发内存实际提交
修改你的代码,对分配的内存进行一次写入操作,强制Windows提交内存页:
IntPtr x = Marshal.AllocHGlobal(100000000); // 写入第一个字节,触发内存提交 Marshal.WriteByte(x, 0, 0); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); Marshal.FreeHGlobal(x); Console.ReadKey(true);
这时候再看任务管理器,就能看到进程的内存占用明显上升了。
2. 使用.NET的Process类获取精确内存数据
你可以通过System.Diagnostics.Process类直接读取进程的内存统计信息,这些数据比任务管理器更精准,能直接反映非托管内存的提交情况:
using System.Diagnostics; // ... IntPtr x = Marshal.AllocHGlobal(100000000); Marshal.WriteByte(x, 0, 0); // 触发提交 var process = Process.GetCurrentProcess(); // PrivateMemorySize64 表示进程的私有提交内存(包括非托管堆) Console.WriteLine($"私有提交内存: {process.PrivateMemorySize64 / 1024 / 1024} MB"); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); Marshal.FreeHGlobal(x); Console.WriteLine($"释放后私有提交内存: {process.PrivateMemorySize64 / 1024 / 1024} MB"); Console.ReadKey(true);
3. 使用专业内存分析工具
- Visual Studio 诊断工具:打开你的项目后,点击“调试”→“显示诊断工具”,选择“内存使用”选项。它可以清晰区分托管堆和非托管堆的内存占用,还能追踪非托管内存的分配点。
- WinDbg:这是Windows官方的调试工具,使用
!heap命令可以查看非托管堆的详细信息,比如已分配块的大小、数量,甚至能定位到具体的分配调用栈。 - Process Explorer:比任务管理器更强大的进程查看工具,它能显示进程的虚拟内存、提交内存、工作集等多个维度的内存数据,还能查看进程的堆信息。
4. 自定义内存跟踪封装
如果是在自己的项目中持续监控非托管内存,你可以封装AllocHGlobal和FreeHGlobal,维护一个全局计数器:
public static class UnmanagedMemoryTracker { private static long _allocatedBytes = 0; private static readonly object _lock = new object(); private static readonly Dictionary<IntPtr, long> _pointerSizes = new Dictionary<IntPtr, long>(); public static long CurrentAllocatedBytes { get { lock (_lock) return _allocatedBytes; } } public static IntPtr AllocHGlobal(long cb) { var ptr = Marshal.AllocHGlobal((int)cb); lock (_lock) { _allocatedBytes += cb; _pointerSizes[ptr] = cb; } return ptr; } public static void FreeHGlobal(IntPtr hglobal) { lock (_lock) { if (_pointerSizes.TryGetValue(hglobal, out long size)) { _allocatedBytes -= size; _pointerSizes.Remove(hglobal); } } Marshal.FreeHGlobal(hglobal); } }
这样你就可以在代码的任何地方通过UnmanagedMemoryTracker.CurrentAllocatedBytes查看当前非托管内存的总占用量,适合自定义的测试和监控场景。
内容的提问来源于stack exchange,提问作者oliver
相关产品推荐
相关产品推荐

