2013-10-27 7 views
6

ECMA-335, heißt es I.12.3.2.4 folgendes:Wo CLR lokalen Speicherpool zuweist?

Ein Teil jeder Verfahrenszustand ein lokaler Speicher-Pool ist. Der Speicher kann explizit aus dem lokalen Speicherpool mit der Anweisung localloc zugewiesen werden. Der gesamte Speicher im lokalen Speicherpool wird beim Methodenexit zurückgewonnen, und nur so wird der Speicher des lokalen Speicherpools wiederhergestellt (es gibt keine Anweisung zum Freigeben von lokalem Speicher, der während dieses Methodenaufrufs zugewiesen wurde). Der lokale Speicherpool wird zum Zuordnen von Objekten verwendet, deren Typ oder Größe zur Kompilierzeit nicht bekannt ist und die der Programmierer nicht im verwalteten Heap reservieren möchte. Da der lokale Speicherpool während der Lebensdauer der Methode nicht verkleinert werden kann, kann eine Sprachimplementierung den lokalen Speicherpool nicht für die allgemeine Speicherzuweisung verwenden.

Wo reserviert CLR diesen Speicherpool? Ist es verwalteter Haufen, Fadenstapel, usw.?

+0

Ich kann mit keiner Autorität sagen, aber es klingt wie Stapelzuweisung für mich. Ich vermute jedoch, dass der Standard dies nicht explizit erfordert, um den Implementierern eine größere Flexibilität zu bieten. – Dweeberly

Antwort

8

Dies ist absichtlich vage, weil es ein starkes Implementierungsdetail ist, das die CLI-Spezifikation nicht festhalten will. Es späht durch die Risse in dem MSDN-Artikel für Opcodes.Localloc aber:

Stackoverflow geworfen wird, wenn nicht genügend Speicher, um die Anforderung zu bedienen.

Es gibt nur eine Möglichkeit, SOE zu bekommen: es erfordert die Zuweisung vom Stack.

Die C# -Sprache ist weniger schüchtern, wo es zugewiesen wird, es verwendet das stackalloc Schlüsselwort. Ein Beispielprogramm:

class Program { 
    static unsafe void Main(string[] args) { 
     int* p = stackalloc int[42]; 
    } 
} 

produziert dieses IL:

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  9 (0x9) 
    .maxstack 8 
    IL_0000: ldc.i4.s 42 
    IL_0002: conv.u 
    IL_0003: ldc.i4.4 
    IL_0004: mul.ovf.un 
    IL_0005: localloc     // <=== Here 
    IL_0007: pop 
    IL_0008: ret 
} // end of method Program::Main 

dem diese Maschinen-Code zur Laufzeit erzeugt:

02E42620 push  ebp 
02E42621 mov   ebp,esp 
02E42623 sub   esp,8 
02E42626 mov   dword ptr [ebp-4],esp 
02E42629 mov   dword ptr [ebp-8],6A029823h 
02E42630 mov   eax,esp 
02E42632 test  dword ptr [esp],esp 
02E42635 sub   eax,0A8h      // <=== Here 
02E4263A mov   esp,eax 
02E4263C mov   dword ptr [ebp-4],esp 
02E4263F cmp   dword ptr [ebp-8],6A029823h 
02E42646 je   02E4264D 
02E42648 call  730CA5C0 
02E4264D lea   esp,[ebp] 
02E42650 pop   ebp 
02E42651 ret 

Die sub eax,0A8h Anweisung 0xa8 = 168 = 42x4 Bytes vom ESP subtrahiert Register (der Stapelzeiger), passt die mov esp,eax Anweisung den Stapelzeiger an. Also ja, das kommt definitiv vom Stapel.