【问题标题】:Process memory does not increase after creating an object?创建对象后进程内存不增加?
【发布时间】: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();
    }

现在有趣的部分开始了。我假设内存在beforeafter 之间增加了 - 但内存消耗总是相同。

[WS64] Diff:   0 bytes
[priv64] Diff:   0 bytes
[PMS64] Diff:   0 bytes
[PSMS64] Diff:   0 bytes

我在这里缺少什么?我还尝试将beforeafterdiff 的输出移动到最底部,以便在转储时将它们保留在内存中,但这似乎没有任何变化 - Diff 始终为零。

【问题讨论】:

  • 当您启动 .NET Framework 应用程序框架时会分配一些内存,然后用于分配您创建的所有对象。它使内存分配更快,因为它不需要与系统进行低级交互来在程序运行时分配少量内存。您的测试项目可能不会强制框架向系统请求更多内存,这就是您看不到任何差异的原因。
  • 这是有道理的。有没有可能查看有多少内存是空闲的并且已经分配了?
  • @ElGauchooo 一个很棒的工具是 VMMap,它可以查看 .NET FW 实际上准备了多少(它也显示未提交的内存,所以不用担心,它可以太字节:D)。另一个很棒的工具是 CLRProfiler,它会显示给定时间应用程序中所有对象的所有实际内存大小。
  • @Luaan 我可以使用 VMMap 或 CLRProfiler 从我自己的代码中以编程方式读取统计信息吗?请参阅我的另一个问题 - 这是我真正想要实现的目标:stackoverflow.com/questions/21575359/…
  • @ElGauchooo 你可以从本机代码中做到这一点,是的。问题是——你为什么要这么做?如果您正在加载插件,请将它们加载到不同的 AppDomain - 然后您可以简单地卸载 AppDomain 并完成。无法查看通用应用程序是否存在内存泄漏(如果可能,您的操作系统可以为您做到这一点:))。此外,您不应该尝试解决由 3rd 方提供商造成的问题 - 这会将所有责任推到您的肩上。相反,让人们自己发现插件写错了,让他们决定是否要使用它们。

标签: c# debugging memory process


【解决方案1】:

您错过了它不是计算保留内存部分中使用的字节数,而是保留内存的大小。仅当使用了所有保留的内存(例如 PrivateMemorySize64)时,运行时才会为该集合分配更多内存。

【讨论】:

    【解决方案2】:

    还有一个问题。由于我使用了由var process = Process.GetCurrentProcess(); 创建的同一进程对象,因此从该对象请求的所有属性都是相同的。为after-dump 重新创建它显示了不同

    [WS64] Diff:   716800 bytes
    [priv64] Diff:   593920 bytes
    [PMS64] Diff:   593920 bytes
    [PSMS64] Diff:   136 bytes
    

    【讨论】:

      【解决方案3】:

      我认为您只需要在读取内存使用统计信息之前调用process.Refresh()

      【讨论】:

        猜你喜欢
        • 2018-05-14
        • 1970-01-01
        • 2014-09-16
        • 2019-10-04
        • 2015-05-25
        • 1970-01-01
        • 2017-04-02
        • 1970-01-01
        • 2020-12-25
        相关资源
        最近更新 更多