C# 创建对象后进程内存不增加?
我目前正试图了解内存属性,如WorkingSet64、PagedMemorySize64等是如何工作的。我已经写了一个小程序,可以调试自己进程的内存消耗 有三类: 用于持久化内存转储的数据:C# 创建对象后进程内存不增加?,c#,debugging,memory,process,C#,Debugging,Memory,Process,我目前正试图了解内存属性,如WorkingSet64、PagedMemorySize64等是如何工作的。我已经写了一个小程序,可以调试自己进程的内存消耗 有三类: 用于持久化内存转储的数据: public class ProcessDTO { public ProcessDTO(long workingSet64, long privateMemorySize64, long pagedSystemMemorySize64, long pagedMemorySize64) {
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; }
}
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;
}
}
进程读取器,首先强制GC运行,然后创建内存转储:
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; }
}
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();
}
现在有趣的部分开始了。我假设,在<代码>之前<代码>和<代码>之后<代码>之间内存会增加,但是内存消耗总是相同的
[WS64] Diff: 0 bytes
[priv64] Diff: 0 bytes
[PMS64] Diff: 0 bytes
[PSMS64] Diff: 0 bytes
我错过了什么?我还尝试将
之前
、之后
和diff
的输出移动到最底部,以便在转储时将它们保存在内存中,但这似乎没有变化-diff始终为零。您缺少的是,它没有计算保留内存部分中使用的字节,但是保留内存的大小。只有使用中的所有保留内存(例如PrivateMemorySize64),运行时才会为该集合分配更多内存 还有一个问题。因为我使用了由var process=process.GetCurrentProcess()创建的相同流程对象代码>,从该对象请求的所有属性都是相同的。在
-dump之后为重新创建它显示了一个差异
[WS64] Diff: 716800 bytes
[priv64] Diff: 593920 bytes
[PMS64] Diff: 593920 bytes
[PSMS64] Diff: 136 bytes
我认为您只需要在读取内存使用统计数据之前调用process.Refresh()
。启动时,.NET Framework应用程序框架会分配一定数量的内存,然后用于分配您创建的所有对象。它使内存分配更快,因为当您的程序运行时,它不需要与系统进行低级交互来分配少量内存。您的测试项目可能不会强制框架向系统请求更多内存,这就是为什么您看不到任何差异。这是有意义的。是否有可能看到有多少内存是空闲的,并且已经分配了?@elgauchoo一个很好的工具是VMMap,它可以查看.NET FW实际准备了多少内存(它也显示未提交的内存,所以不要担心,它可以是TB:D)。另一个很棒的工具是CLRProfiler,它将在给定时间向您显示应用程序中所有对象的所有实际内存大小。@Luaan我可以使用VMMap或CLRProfiler以编程方式从自己的代码中读取统计信息吗?请看我的另一个问题——这是我真正想要实现的:@elgauchoo您可以从本机代码实现这一点,是的。问题是——你为什么要这么做?如果您正在加载插件,请将它们加载到不同的AppDomain中,然后您只需卸载AppDomain即可。无法查看一般应用程序是否存在内存泄漏(如果可能,您的操作系统可以为您做到:))。此外,您不应该试图解决由第三方提供商造成的问题,这会将所有责任推到您的肩上。相反,让人们发现自己的插件写错了,让他们决定是否要使用它们。