如何在.NET运行时移动存储?移动存储、如何在、NET

2023-09-03 06:46:37 作者:沫殇

这是一个众所周知的事实是,.NET垃圾回收器不会只是删除的对象在堆上,还打架使用内存压缩内存碎片。据我了解,基本上是内存复制到一个新的地方,和老的地方是在某一时刻被删除。

It's a well known fact that the .NET garbage collector doesn't just 'delete' the objects on the heap, but also fights memory fragmentation using memory compaction. From what I understand, basically memory is copied to a new place, and the old place is at some point deleted.

我的问题是:如何工作的呢?

My question is: how does this work?

什么我最好奇的是,GC运行在一个单独的线程,这意味着我们正在处理的对象可以通过GC的当我们执行我们的$ C $移动的事实ç的。

What I'm mostly curious about is the fact that the GC runs in a separate thread, which means that the object we're working on can be moved by the GC while we're executing our code.

问题的技术细节

要说明这一点,让我解释一下我的问题的详细信息:

To illustrate, let me explain my question in more detail:

class Program
{
    private int foo;
    public static void Main(string[] args)
    {
        var tmp = new Program(); // make an object
        if (args.Length == 2)    // depend the outcome on a runtime check
        {
            tmp.foo = 12;        // set value ***
        }
        Console.WriteLine(tmp.foo);
    }
}

在这个小例子中,我们创建了一个对象,并在对象上设置一个简单的变量。点'***'才是最重要的问题是:如果TMP的地址移动,'富'将引用不正确的东西,一切都将打破

In this small example, we create an object and set a simple variable on an object. The point '***' is all that matters for the question: if the address of 'tmp' moves, 'foo' will reference something incorrect and everything will break.

垃圾收集器运行在独立的线程中。所以,据我所知,TMP可以在本指令和'富'期间,移动可以结束了不正确的值。但不知何故,奇迹发生了,它没有。

The garbage collector runs in a separate thread. So as far as I know, 'tmp' can be moved during this instruction and 'foo' can end up with the incorrect value. But somehow, magic happens and it doesn't.

至于反汇编器,我注意到编译的程序真的需要的'富'和移动的地址中的值'12:

As for the disassembler, I noticed that the compiled program really takes the address of 'foo' and moves in the value '12:

000000ae 48 8B 85 10 01 00 00 mov         rax,qword ptr [rbp+00000110h] 
000000b5 C7 40 08 0C 00 00 00 mov         dword ptr [rax+8],0Ch 

余或多或少期望看到的间接指针这里,可以是updated-但显然对GC工作比聪明

I more or less expected to see an indirect pointer here, which can be updated- but apparently the GC works smarter than that.

另外,我看不出有任何的线程同步来检查,如果该对象已被移动。那么,如何在GC更新正在执行的线程的状态?

Further, I don't see any thread synchronization that checks if the object has been moved. So how does the GC update the state in the executing thread?

那么,如何工作的呢?而如果GC不动这些对象,什么是规则的定义羯羊或不移动的对象?

So, how does this work? And if the GC doesn't move these objects, what is the 'rule' that defines wether or not to move the objects?

推荐答案

在.NET GC(至少部分地)一个停了世界的GC:将停止管理线程做它的工作之前,做其工作,然后重新启动托管线程。

The .NET GC is (at least partially) a "stop-the-world" GC: it stops managed threads before doing its work, does its work, then restarts managed threads.

工作站GC可以的并行的(所以部分不能阻止这世界),但要注意在的 https://msdn.microsoft.com/library/ee851764.aspx 。

The "Workstation" GC can be concurrent (so partially not stop-the-world) but note at https://msdn.microsoft.com/library/ee851764.aspx .

当您使用工作站垃圾收集并发垃圾回收,回收的对象不板结,所以堆的大小可以相同或更大(碎片可以使它看起来更大)。

When you are using workstation garbage collection with concurrent garbage collection, the reclaimed objects are not compacted, so the heap size can be the same or larger (fragmentation can make it appear to be larger).

请注意,与所有的GC,gen0和第一代总是停了世界。因此,他们可以移动的内存块没有问题。只有第二代可以在后台通过与一些配置一些GC(这链接的信息来完成有点支离破碎的所有页面各处),所以总有一个的世界,是-停止时刻,已经释放的内存可以被压缩。

Note that with all the GC, gen0 and gen1 are always stop-the-world. So they can move blocks of memory without problems. Only gen2 can be done in background by some GC with some configurations (this link, the information is a little fragmented all around the page), so there is always a "the-world-is-stopped" moment where the memory that has been freed can be compacted.