如何获取运行中C#应用的原生内存使用量(类似jcmd细粒度数据)
获取C#应用的非托管内存使用量(等价jcmd VM.native_memory非堆部分)
一、应用内部获取(可作为追踪指标)
1. 非托管内存总量计算
通过进程内存数据减去托管堆内存,得到近似的非托管内存总量:
using System.Diagnostics; public static long GetUnmanagedMemoryTotal() { var process = Process.GetCurrentProcess(); // 进程私有内存总量(包含托管堆、非托管堆、加载模块等) long privateMemory = process.PrivateMemorySize64; // 强制GC后获取托管堆已提交的总内存,结果更准确 long managedMemory = GC.GetTotalMemory(true); // 非托管内存总量(近似值) return privateMemory - managedMemory; }
注:该结果包含CLR自身的非托管结构、第三方非托管DLL内存等,是进程级非托管内存的近似统计,满足总量追踪需求。
2. 精确追踪Marshal.AllocHGlobal类分配
如果核心目标是追踪Marshal.AllocHGlobal/Marshal.FreeHGlobal这类手动非托管分配,可以封装线程安全的追踪工具类:
using System.Runtime.InteropServices; using System.Threading; using System.Collections.Concurrent; public static class UnmanagedAllocatorTracker { private static long _totalAllocatedBytes = 0; private static readonly ConcurrentDictionary<IntPtr, int> _allocationMap = new(); public static IntPtr AllocHGlobal(int cb) { var ptr = Marshal.AllocHGlobal(cb); _allocationMap.TryAdd(ptr, cb); Interlocked.Add(ref _totalAllocatedBytes, cb); return ptr; } public static void FreeHGlobal(IntPtr ptr) { if (_allocationMap.TryRemove(ptr, out int allocatedSize)) { Interlocked.Add(ref _totalAllocatedBytes, -allocatedSize); } Marshal.FreeHGlobal(ptr); } public static long GetTotalAllocatedBytes() { return Interlocked.Read(ref _totalAllocatedBytes); } }
该类通过维护分配映射表,能精确统计
Marshal.AllocHGlobal系列调用的总分配内存,适合作为自定义追踪指标。
二、外部CLI工具获取
1. dotnet-counters(官方推荐,实时监控)
这是.NET官方轻量级性能监控工具,无需调试环境,可实时获取内存指标:
- 安装:
dotnet tool install --global dotnet-counters - 运行:找到目标进程PID后执行:
重点关注输出中的两个字段:dotnet counters monitor --process-id <目标进程PID> System.RuntimePrivate Bytes:进程私有内存总量Heap Size:托管堆已使用内存
两者差值即为非托管内存总量;若需更细粒度数据,可添加对应业务组件的计数器组(如Microsoft.AspNetCore.Hosting)。
2. 系统原生工具
- Windows:用
tasklist查看进程内存:
结合tasklist /fi "PID eq <PID>" /v /fo listdotnet-counters的托管堆数据,可计算非托管内存总量。 - Linux/macOS:用
ps命令查看内存:ps -o rss,vsize -p <PID>vsize为虚拟内存总量,rss为驻留集大小,搭配托管堆数据可估算非托管内存。
内容的提问来源于stack exchange,提问作者andresp
相关产品推荐
相关产品推荐

