【发布时间】:2014-02-06 08:30:58
【问题描述】:
我目前正在尝试了解 WorkingSet64、PagedMemorySize64 等内存属性如何。我写了一个小程序,可以调试自己进程的内存消耗。
共有三个类:
用于持久化内存转储的 DTO:
public class ProcessDTO
{
public ProcessDTO(long workingSet64, long privateMemorySize64, long pagedSystemMemorySize64, long pagedMemorySize64)
{
WorkingSet64 = workingSet64;
PrivateMemorySize64 = privateMemorySize64;
PagedSystemMemorySize64 = pagedSystemMemorySize64;
PagedMemorySize64 = pagedMemorySize64;
}
public long WorkingSet64 { get; private set; }
public long PrivateMemorySize64 { get; private set; }
public long PagedSystemMemorySize64 { get; private set; }
public long PagedMemorySize64 { get; private set; }
}
进程读取器,它首先强制 GC 运行,然后创建内存转储:
internal class ProcessDumper
{
public ProcessDTO GetProcessDump(Process process)
{
GC.Collect();
GC.WaitForPendingFinalizers();
var workingSet64 = process.WorkingSet64;
var privateMemorySize64 = process.PrivateMemorySize64;
var pagedSystemMemorySize64 = process.PagedSystemMemorySize64;
var pagedMemorySize64 = process.PagedMemorySize64;
var result = new ProcessDTO(workingSet64, privateMemorySize64, pagedSystemMemorySize64, pagedMemorySize64);
return result;
}
}
最后是我的控制台应用程序:
static void Main(string[] args)
{
var processDumper = new ProcessDumper();
var process = Process.GetCurrentProcess();
var before = processDumper.GetProcessDump(process);
Console.WriteLine("[WS64] Before: {0} bytes", before.WorkingSet64);
Console.WriteLine("[priv64] Before: {0} bytes", before.PrivateMemorySize64);
Console.WriteLine("[PMS64] Before: {0} bytes", before.PagedMemorySize64);
Console.WriteLine("[PSMS64] Before: {0} bytes", before.PagedSystemMemorySize64);
Console.WriteLine();
var foo = new byte[]
{
0x10, 0x99, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x04, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
};
var max = foo.Max();
Console.WriteLine("Just to do something with my object... max is {0}", max);
var after = processDumper.GetProcessDump(process);
var min = foo.Min();
Console.WriteLine("Just to do something with my object... min is {0}", min);
Console.WriteLine();
Console.WriteLine("[WS64] After: {0} bytes", after.WorkingSet64);
Console.WriteLine("[priv64] After: {0} bytes", after.PrivateMemorySize64);
Console.WriteLine("[PMS64] After: {0} bytes", after.PagedMemorySize64);
Console.WriteLine("[PSMS64] After: {0} bytes", after.PagedSystemMemorySize64);
Console.WriteLine();
Console.WriteLine("[WS64] Diff: {0} bytes", (after.WorkingSet64 - before.WorkingSet64));
Console.WriteLine("[priv64] Diff: {0} bytes", (after.PrivateMemorySize64 - before.PrivateMemorySize64));
Console.WriteLine("[PMS64] Diff: {0} bytes", (after.PagedMemorySize64 - before.PagedMemorySize64));
Console.WriteLine("[PSMS64] Diff: {0} bytes", (after.PagedSystemMemorySize64 - before.PagedSystemMemorySize64));
Console.ReadLine();
}
现在有趣的部分开始了。我假设内存在before 和after 之间增加了 - 但内存消耗总是相同。
[WS64] Diff: 0 bytes
[priv64] Diff: 0 bytes
[PMS64] Diff: 0 bytes
[PSMS64] Diff: 0 bytes
我在这里缺少什么?我还尝试将before、after 和diff 的输出移动到最底部,以便在转储时将它们保留在内存中,但这似乎没有任何变化 - Diff 始终为零。
【问题讨论】:
-
当您启动 .NET Framework 应用程序框架时会分配一些内存,然后用于分配您创建的所有对象。它使内存分配更快,因为它不需要与系统进行低级交互来在程序运行时分配少量内存。您的测试项目可能不会强制框架向系统请求更多内存,这就是您看不到任何差异的原因。
-
这是有道理的。有没有可能查看有多少内存是空闲的并且已经分配了?
-
@ElGauchooo 一个很棒的工具是 VMMap,它可以查看 .NET FW 实际上准备了多少(它也显示未提交的内存,所以不用担心,它可以太字节:D)。另一个很棒的工具是 CLRProfiler,它会显示给定时间应用程序中所有对象的所有实际内存大小。
-
@Luaan 我可以使用 VMMap 或 CLRProfiler 从我自己的代码中以编程方式读取统计信息吗?请参阅我的另一个问题 - 这是我真正想要实现的目标:stackoverflow.com/questions/21575359/…
-
@ElGauchooo 你可以从本机代码中做到这一点,是的。问题是——你为什么要这么做?如果您正在加载插件,请将它们加载到不同的 AppDomain - 然后您可以简单地卸载 AppDomain 并完成。无法查看通用应用程序是否存在内存泄漏(如果可能,您的操作系统可以为您做到这一点:))。此外,您不应该尝试解决由 3rd 方提供商造成的问题 - 这会将所有责任推到您的肩上。相反,让人们自己发现插件写错了,让他们决定是否要使用它们。
标签: c# debugging memory process