代码之家  ›  专栏  ›  技术社区  ›  recursive

如何获得总堆分配?GC。GetAllocatedBytesForCurrentThread()无法执行此操作

  •  0
  • recursive  · 技术社区  · 4 年前

    我想知道一个线程累计分配了多少内存。从它的文档中 GC.GetAllocatedBytesForCurrentThread() 似乎是要用的东西,但实际上,它给了我。。。还有别的。

    using System;
    
    class Program {
        static void Main() {
            long start, difference;
    
            start = GC.GetAllocatedBytesForCurrentThread();
            var x = new int[1_000_000];
            difference = GC.GetAllocatedBytesForCurrentThread() - start;
            Console.WriteLine("{0} bytes allocated for array construction", difference);
    
            start = GC.GetAllocatedBytesForCurrentThread();
            Console.WriteLine(DateTime.Now.ToString());
            difference = GC.GetAllocatedBytesForCurrentThread() - start;
            Console.WriteLine("{0} bytes allocated for date printing", difference);
        }
    }
    

    它给了我这个输出。

    0 bytes allocated for array construction
    9/17/2020 11:26:40 AM
    19040 bytes allocated for date printing
    Press any key to continue . . .
    

    我不相信不在堆上分配一个字节就可以创建一个100万元素的数组。

    那么,有没有一种方法可以跟踪线程的堆分配?这个方法到底在做什么,如果有的话?

    这里有一个更长、更全面的测试计划,包括到目前为止的所有建议。我包含了求和部分,以验证在代码运行时是否确实创建了数组。

    using System;
    using System.Linq;
    
    class Program {
        static void Main() {
            long start, difference;
    
            {
                start = GC.GetAllocatedBytesForCurrentThread();
                var x = new int[1_000_000];
                x[^1] = 7;
                difference = GC.GetAllocatedBytesForCurrentThread() - start;
                Console.WriteLine("{0} bytes thread allocated for array construction (sum: {1})", difference, x.Sum());
            }
    
            start = GC.GetAllocatedBytesForCurrentThread();
            Console.WriteLine(DateTime.Now.ToString());
            difference = GC.GetAllocatedBytesForCurrentThread() - start;
            Console.WriteLine("{0} bytes thread allocated for date printing", difference);
    
            {
                start = GC.GetTotalMemory(true);
                var x = new int[1_000_000];
                x[^1] = 7;
                difference = GC.GetTotalMemory(true) - start;
                Console.WriteLine("{0} bytes total allocated for array construction (sum: {1})", difference, x.Sum());
            }
    
            start = GC.GetTotalMemory(true);
            Console.WriteLine(DateTime.Now.ToString());
            difference = GC.GetTotalMemory(true) - start;
            Console.WriteLine("{0} bytes total allocated for date printing", difference);
    
        }
    }
    

    输出:

    0 bytes thread allocated for array construction (sum: 7)
    9/17/2020 11:51:54 AM
    19296 bytes thread allocated for date printing
    4000024 bytes total allocated for array construction (sum: 7)
    9/17/2020 11:51:54 AM
    64 bytes total allocated for date printing                                                                              
    
    0 回复  |  直到 4 年前
        1
  •  0
  •   user12031933 user12031933    4 年前

    通过以下IL代码进行阵列分配:

    // int[] array = new int[1000000];
    IL_0008: ldc.i4 1000000
    IL_000d: newarr [mscorlib]System.Int32
    IL_0012: stloc.2
    

    阅读并不能提供很多帮助:

    https://docs.microsoft.com/dotnet/api/system.reflection.emit.opcodes.newarr

    但也许数组是由CLR中的另一个线程创建的,实际上是由CLR线程本身创建的,我认为这就是原因 GC.GetAllocatedBytesForCurrentThread() - start 返回 0 使用时 GetTotalMemory 返回正确且真实的金额。

    数组在堆中分配,而本地值类型和引用直接在方法的堆栈中创建。

    例如:

    .locals init (
        [0] int64 'value'
    )
    
    IL_0001: ldc.i4.s 10
    IL_0003: conv.i8
    IL_0004: stloc.0
    

    因此,在所有情况下,当前线程都不会消耗任何东西。

    但如果你创造了一个 List<int> 接下来添加一些项目,或者做任何消耗内存的事情,比如调用medthods( DateTime.Now.ToString() ),线程将消耗内存,您将看到使用 GetAllocatedBytesForCurrentThread 方法

    但是在数组的情况下,如果是CLR线程创建了它们,我们看不到这一点。