繁体   English   中英

如何获得总堆分配? GC.GetAllocatedBytesForCurrentThread() 不这样做

[英]How can I get total heap allocations? GC.GetAllocatedBytesForCurrentThread() doesn't do it

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

这是我的测试程序,使用 dotnet core 3.1 控制台应用程序 Visual Studio 模板创建。

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 . . .

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

那么有没有办法跟踪线程的堆分配? 如果有的话,这种方法实际上在做什么?

这是一个更长、更全面的测试程序,包括迄今为止的所有建议。 我包含了 sum 部分来验证在代码运行时确实创建了数组。

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                                                                              

数组分配是由这个 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 线程,我们就看不到这一点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM