Frage

I am looking for a detailed description on what happens in the CLR for C# code that accesses an array index / object member. Consider the following:

int myVal = myObjArray[1].MyObjFieldB;

The C# Compiler compiles this to something along the lines of:

IL_0001:  ldc.i4.1
IL_0002:  ldelem.ref
IL_0003:  ldfld      int32 MyProgram.myObj::MyObjFieldB
IL_0008:  pop

But what happens when executing the program? How does the CLR figure out the correct memory locations for the array and the object? How does it ensure that GC does not interfere?

An answer based on Mono would be as valuable (especially with pointers to the source).

War es hilfreich?

Lösung

"Interfere" isn't exactly the right word, it is one of the GC's important duties to find the pointer back and update its value.

Finding the pointer first is the most important job, that's how the GC knows that the array is still used and should not be collected. The jitter plays a very important role in this. When it translate the IL to machine code it performs an obvious and very visible job of generating the code. But also does another job that completely invisible, it generates a table that describes exactly where object references are stored inside the method. It contains table entries for both CPU registers and stack frame locations, indexed by code address. The GC needs this table to find the object reference back.

So from there, after building the object graph, determining what objects are still live and compacting the heap, the last thing it does is update the pointer value if the object was moved. Patching the stack location or the stored CPU register value. So that, after the code resumes, it now uses the correct pointer again.

Andere Tipps

Step 1:

Load the array reference. This can be done with basically any load operation, for example ldloc.0 (Load local variable 0)

The stack:

Reference to myObjArray

Step 2:

Load the index. This can also be done with any load operation, for example ldc.i4.1 (Load constant as 4-byte int with value 1)

The stack:

1
Reference to myObjArray

Step 3:

Index into the array. This is done with the ldelem (Load element) family of opcodes. Here it's ldelem.ref (Load element reference) because it's loading a reference from the array.

The stack:

Reference to myObjArray[1]

Step 4:

Get the field, using ldfld (Load field value) and passing a field.

The stack:

myObjArray[1].MyObjFieldB

Step 5:

Store the value. This would probably be done with an stloc (Store to local variable) opcode, but in your case, it's just discarded with a pop.


All references in .NET are simply memory addresses, stored much like normal variables.

If the GC does run during this, it won't remove anything, and it will transparently reassign all the references to new values, and your code won't even notice.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top