2014-09-16 9 views
7

Ho un OutOfMemoryException e mi piacerebbe analizzare la dimensione e il tipo dell'array che deve essere creato.Come identificare il tipo di array?

ho creato una discarica scopo demo per questa situazione e sono in grado di ottenere le seguenti informazioni:

0:000> !pe 
Exception object: 023f389c 
Exception type: System.OutOfMemoryException 
Message: <none> 
InnerException: <none> 
StackTrace (generated): 
    SP  IP  Function 
    0015EE44 0099007F OOM2!OOM2.Program.Main()+0xf 

StackTraceString: <none> 
HResult: 8007000e 

0:000> !u 0099007F 
Normal JIT generated code 
OOM2.Program.Main() 
Begin 00990070, size 22 
00990070 baffffff7f  mov  edx,7FFFFFFFh 
00990075 b90241a478  mov  ecx,offset mscorlib_ni+0x4102 (78a44102) 
0099007a e8192194ff  call 002d2198 (JitHelp: CORINFO_HELP_NEWARR_1_VC) 
>>> 0099007f 8bc8   mov  ecx,eax 
... 

così posso vedere che si crea un nuovo array e la dimensione è 7FFFFFFF, che è 2 miliardi di articoli. (Si prega di ignorare il fatto che non si può nemmeno creare un byte [] di quella dimensione in un'applicazione .NET a 32 bit, quindi in questo esempio il tipo probabilmente non importa affatto.)

Ho letto ora che il tipo di array è nel registro ECX, ma sfortunatamente lo mscorlib_ni+0x4102 (78a44102) non è molto utile.

ho cercato !mln, !mdt e anche irrealistico !ip2mt, ma nessuno di loro mostra la byte o byte[] risultati attesi. C'è un modo per ottenere il tipo dall'immagine nativa di mscorlib?

+0

Il tipo di matrice viene effettivamente passato in ECX. Tuttavia, piuttosto che un normale token di metadati, è un "handle to a metadata token". Questo è generato dal JIT. Non sono a conoscenza di un modo per passare da un handle al token di metadati originale. Piuttosto, poiché l'IL esiste, è più semplice visualizzarlo per identificare il tipo di matrice. – Dono

risposta

3

Un modo per farlo è quello di eseguire il dump del IL corrispondente al metodo che l'array è stato creato in.

In primo luogo, utilizzare !clrstack per ottenere il metodo si è in. Nel mio caso io sono in un'applicazione fittizia nel metodo Main:

0:000> !clrstack 
OS Thread Id: 0x7d0 (0) 
Child SP  IP Call Site 
0016f094 758dc42d [HelperMethodFrame: 0016f094] 
0016f120 003200af ConsoleApplication4.Program.Main(System.String[]) [c:\Users\smt\Documents\Visual Studio 2012\Projects\ConsoleApplication4\Program.cs @ 215] 
0016f2bc 743b3de2 [GCFrame: 0016f2bc] 

uso successivo !name2ee per ottenere il metodo disc di questo metodo (il comando successivo ne ha bisogno):

0:000> !name2ee ConsoleApplication4!ConsoleApplication4.Program.Main 
Module:  00282eac 
Assembly: ConsoleApplication4.exe 
Token:  0600013c 
MethodDesc: 00283dbc 
Name:  ConsoleApplication4.Program.Main(System.String[]) 
JITTED Code Address: 00320050 

Ora, eseguire il dump dei IL del metodo:

0:000> !dumpil 00283dbc 
ilAddr = 002d4bc4 
IL_0000: nop 
IL_0001: newobj class [mscorlib]System.Collections.Generic.List`1<?????? ??????n?.::.ctor 
IL_0006: stloc.0 
IL_0007: br.s IL_001e 
IL_0009: nop 
IL_000a: ldc.i4 2147483647 
IL_000f: newarr System.Single 
IL_0014: stloc.1 
IL_0015: ldloc.0 
IL_0016: ldloc.1 
IL_0017: callvirt class [mscorlib]System.Collections.Generic.List`1<?????? ??????N?.::Add 
IL_001c: nop 
IL_001d: nop 
IL_001e: ldc.i4.1 
IL_001f: stloc.2 
IL_0020: br.s IL_0109 

Per fare un confronto, questo è il mio metodo in C#:

static void Main(string[] args) 
{ 
    List<float[]> arrays = new List<float[]>(); 
    while (true) 
    { 
     float[] f = new float[Int32.MaxValue]; 
     arrays.Add(f); 
    } 

    Console.ReadKey(); 
} 

Si può vedere on line IL_000f che viene creato un nuovo array di tipo System.Single .


Sono andato giù per questa strada perché non riesco a decifrare l'argomento passato al vero metodo nativo che crea l'array. Se si esegue kb al punto viene generata l'eccezione:

0:000> kb 
ChildEBP RetAddr Args to Child    
WARNING: Stack unwind information not available. Following frames may be wrong. 
0016efa4 74502a42 e0434352 00000001 00000005 KERNELBASE!RaiseException+0x58 
0016f048 745d55ef 00000000 bc1d0b3d 0016f10c clr!RaiseTheExceptionInternalOnly+0x276 
0016f078 7464ae51 bc1d0a7d 0016f150 00000000 clr!UnwindAndContinueRethrowHelperAfterCatch+0x83 
0016f118 003200af 00000000 02202480 00000000 clr!JIT_NewArr1+0x1af 
0016f138 743b3de2 00720198 0016f198 743c3315 0x3200af 
0016f144 743c3315 0016f1dc 0016f188 74502c66 clr!CallDescrWorkerInternal+0x34 
... 

Si può vedere che clr!JIT_NewArr1 viene chiamato, che crea un array monodimensionale. Per farlo, it needs the type and the size. Questi argomenti vengono copiati in ecx e edx rispettivamente:

0:000> !u 003200AF 
... 
003200a0 b9e2302a73  mov  ecx,offset mscorlib_ni+0x30e2 (732a30e2) 
003200a5 baffffff7f  mov  edx,7FFFFFFFh 
003200aa e89121f5ff  call 00272240 (JitHelp: CORINFO_HELP_NEWARR_1_VC) 
>>> 003200af 8945e8   mov  dword ptr [ebp-18h],eax 
003200b2 8b45e8   mov  eax,dword ptr [ebp-18h] 
003200b5 8945f0   mov  dword ptr [ebp-10h],eax 
... 

Come si può vedere, ecx ottiene 732a30e2, che mappa in qualche modo le informazioni sul tipo per System.Single, ma non riesco a capire come ...

Problemi correlati