C# 创建对象后进程内存不增加?

C# 创建对象后进程内存不增加?,c#,debugging,memory,process,C#,Debugging,Memory,Process,我目前正试图了解内存属性,如WorkingSet64、PagedMemorySize64等是如何工作的。我已经写了一个小程序,可以调试自己进程的内存消耗 有三类: 用于持久化内存转储的数据: public class ProcessDTO { public ProcessDTO(long workingSet64, long privateMemorySize64, long pagedSystemMemorySize64, long pagedMemorySize64) {

我目前正试图了解内存属性,如WorkingSet64、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即可。无法查看一般应用程序是否存在内存泄漏(如果可能,您的操作系统可以为您做到:))。此外,您不应该试图解决由第三方提供商造成的问题,这会将所有责任推到您的肩上。相反,让人们发现自己的插件写错了,让他们决定是否要使用它们。