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

标签 c# .net-core garbage-collection

我想了解一个线程累计分配了多少内存。从它的文档来看,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 . . .

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

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

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

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://learn.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 线程创建它们,我们就看不到了。

关于c# - 我如何获得总堆分配? GC.GetAllocatedBytesForCurrentThread() 不这样做,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63944229/

相关文章:

C# asp.net 将具有 long 属性的对象传递给前端会更改它的值

c# - .NET Core IServiceScopeFactory.CreateScope() 与 IServiceProvider.CreateScope() 扩展

asp.net-core - data-ajax-update 和 data-ajax-mode ="replace"在 dotnet core jquery unobtrusive ajax 中不起作用

java - Java VisualVM 中的 Visual GC 通过 jstadt 用于远程 Tomcat

java - 为什么下面的代码中finalize没有给出空指针异常?

c++ - 使用 shared_ptr 时如何检测循环

c# - asp.net ListBox控件的高度设置方法

c# - 在 LINQ 中将 datetime2 转换为字符串 ("dd/MM/yyyy")

c# - 批量HQL插入

c# - EF Core 2.0 包含具有动态查询的嵌套实体