为什么c++ /CLI锯齿托管数组初始化器分配巨大的临时数组?



我在工作中分析了一个c++/CLI项目,它有一个奇怪的内存签名:它有大量的已提交字节(7GB),但它在工作集中只有大约30MB。我发现问题出在下面这段代码中:

ref class c1
{
public:
    int x;
    static void createArray()
    {
        auto val = gcnew c1;
        auto arr = gcnew array<c1^>(1) { val };
        auto jagged= gcnew array<array<c1^>^>{ arr };
        //Make sure the array doesn't get optimized away
        Console::WriteLine(jagged[0][0]->x);
    }
};

我期望jaged的初始化在c#中转换成这样的东西:

var jagged = new c1[][] { arr };
相反,使用ILSpy,我发现它实际上翻译成这样的东西(反编译优化的二进制文件:
public static void createArray()
{
    c1 val = new c1();
    c1[] array = new c1[]
    {
        val
    };
    c1[][] array2 = new c1[][]
    {
        new c1[12648430] //the constant is equal to 0xC0FFEE
    };
    array2[0] = array;
    Console.WriteLine(array2[0][0].x);
}

我发现很难理解为什么它会分配一个12648430元素的临时数组。然而,我也很难想象这样的错误实际上是在Visual Studio 2013专业版MSVC编译器中发布的,但我想不出任何其他解释。

我错过了什么吗?

这实际上是c++/CLI编译器实现中的一个bug。微软已经意识到这个问题,但他们暂时不会修复它。

更多细节可以在这里的bug报告中找到。

报告还提出了两个简单的解决方法:

  1. 手动初始化数组,而不是使用初始化列表

  2. 使用二维数组代替锯齿数组