【问题标题】:C#: new[] does not seem to allocate memory in DebugC#:new[] 似乎没有在 Debug 中分配内存
【发布时间】:2014-04-02 22:37:59
【问题描述】:

我尝试将一大块内存分配为字节数组 (400MB)

    public static void Main(string[] args)
    {
        const int MegaByte = 1048576;

        byte[] bytes = new byte[400 * MegaByte];

        for (int i = 0; i < bytes.Length; i++)
        {
            bytes[i] = 3;
        }

        Console.WriteLine("Total array length : {0}", bytes.Length);
        Console.WriteLine("First byte = '{0}' Last byte = '{1}'", bytes[0], bytes[bytes.Length - 1]);
        Console.Read();
    }

输出:

Total array length : 419430400
First byte = '3' Last byte = '3'

正如预期的那样,当我刚刚分配了 400MB 内存时,我在 Windows 任务管理器中看到正在使用的内存大幅跃升。但是,如果我将 forloop 用法替换为仅使用第一个和最后一个字节:

    public static void Main(string[] args)
    {
        const int MegaByte = 1048576;

        byte[] bytes = new byte[400 * MegaByte];

        bytes[0] = 0;
        bytes[bytes.Length - 1] = 2;

        Console.WriteLine("Total array length : {0}", bytes.Length);
        Console.WriteLine("First byte = '{0}' Last byte = '{1}'", bytes[0], bytes[bytes.Length - 1]);
        Console.Read();
    }     

输出:

Total array length : 419430400
First byte = '0' Last byte = '2'

即使分配的数组的长度据说相同,也没有观察到已用内存的大幅跳跃。我有一个假设,如果我们在 Debug 中构建,就不会有这样的优化。是否有一些优化是在“调试”构建期间完成的,或者在编译 IL 时这些事情会在较低级别进行优化吗?

【问题讨论】:

  • GC.GetTotalMemory() 在您的数组前后返回什么?可能是任务管理器未报告当前未使用的内容。
  • 在这两种情况下,GC.GetTotalMemory() 都显示了419432348 从分配前到分配后的跳跃,所以这可能是正在发生的事情。

标签: c# memory optimization build


【解决方案1】:

调试/发布模式优化只是指令优化(IL -> 本机代码编译、内联、指令重新排序等 - 除了始终使用的 const 折叠之外的所有内容)。这不会改变内存的管理方式,它只会改变你的代码流和内存的访问方式。当您查看 IL 代码并将其与相应的汇编代码进行比较时,您可以看到这一点:大多数 IL 代码只是定义了访问/使用内存的方式;分配和解除分配始终由 GC 管理(使用简写,例如 newobjnewarr)。

影响内存行为的唯一方法是通过更改设置来影响 GC。 GC的相关设置可以在这里找到:http://msdn.microsoft.com/en-us/library/6bs4szyc(v=vs.110).aspx

因此,在所有情况下,内存都是由 GC 管理的,它从内核中获取内存(我猜是使用 calloc)并将内存(free)释放给内核。在您的情况下,已分配内存(为数据保留地址空间),但未提交。一旦您访问一个页面 (4 KB),它就会被提交并显示出来。

【讨论】:

    【解决方案2】:

    据我所知,调试和非调试构建之间的对象分配没有优化。

    猜猜-您在任务管理器中查看的最有可能的数字是提交页面,而在大型对象堆上分配大型数组可能只是保留地址空间并允许操作系统在访问时提交/归零内存。您应该能够通过访问数组的每个 4K 元素来确认它。

    【讨论】:

      猜你喜欢
      • 2018-11-10
      • 2017-05-16
      • 2014-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-09
      • 1970-01-01
      • 2011-06-17
      相关资源
      最近更新 更多