当前位置:Gxlcms > 数据库问题 > Windbg探索之.NET内存管理方式

Windbg探索之.NET内存管理方式

时间:2021-07-01 10:21:17 帮助过:25人阅读

using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace WindbugDemo 7 { 8 public class MemoryApply 9 { 10 public long Ticks { get; set; } 11 public int MemSize { get; set; } 12 private byte[] AllocateByte; 13 14 private void AllocateMemory() 15 { 16 AllocateByte = new byte[this.MemSize*1000]; 17 } 18 public MemoryApply(long ticks,int size) 19 { 20 this.Ticks = ticks; 21 this.MemSize = size; 22 this.AllocateMemory(); 23 } 24 25 public string Allocated() 26 { 27 string text = "TicksId = "+Ticks.ToString()+":"+this.MemSize.ToString() + " K memory is allocated!"; 28 return text; 29 } 30 31 public string Released() 32 { 33 string text = "TicksId = " + Ticks.ToString() + ":" + this.MemSize.ToString() + " K memory is released!"; 34 return text; 35 } 36 } 37 38 public class MemoryGen 39 { 40 [STAThread] 41 static void Main(string[] args) 42 { 43 Queue<MemoryApply> queue = new Queue<MemoryApply>(); 44 Random random = new Random(); 45 while (true) 46 { 47 int size = random.Next(60, 120); 48 MemoryApply apply = new MemoryApply(DateTime.UtcNow.Ticks, size); 49 Console.WriteLine(apply.Allocated()); 50 queue.Enqueue(apply); 51 if (queue.Count > 2) 52 { 53 MemoryApply release = queue.Dequeue(); 54 if (release.MemSize > 90) 55 { 56 Console.WriteLine(release.Released()); 57 release = null; 58 } 59 System.GC.Collect(); 60 } 61 System.Threading.Thread.Sleep(500); 62 } 63 } 64 } 65 }

3、还是跟以前调试一样,我们用Windbg打开编译后的EXE文件。

Opened log file d:\log\mem11.txt
0:000> sxe ld:clrjit
0:000> g
(ad0.a2c): Unknown exception - code 04242420 (first chance)
ModLoad: 6f290000 6f30d000   C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll
eax=00000000 ebx=00000000 ecx=011737a4 edx=08000000 esi=7ffde000 edi=001be8d0
eip=778f70b4 esp=001be7e8 ebp=001be83c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!KiFastSystemCallRet:
778f70b4 c3              ret
0:000> .loadby sos clr
0:000> !dumpdomain
...

--------------------------------------
Domain 1:           00334d38
LowFrequencyHeap:   0033518c
HighFrequencyHeap:  003351d4
StubHeap:           0033521c
Stage:              OPEN
SecurityDescriptor: 00336908
...

Assembly:           0038fb80 [D:\bin\MemoryGen.exe]
ClassLoader:        0038fc48
SecurityDescriptor: 0038f820
  Module Name
01172edc    D:\bin\MemoryGen.exe

0:000> !dumpmodule -mt 01172edc    
Name:       D:\bin\MemoryGen.exe
Attributes: PEFile 
Assembly:   0038fb80
LoaderHeap:              00000000
TypeDefToMethodTableMap: 01170038
TypeRefToMethodTableMap: 01170048
MethodDefToDescMap:      01170090
FieldDefToDescMap:       011700bc
MemberRefToDescMap:      00000000
FileReferencesMap:       011700d0
AssemblyReferencesMap:   011700d4
MetaData start address:  0121223c (1836 bytes)

Types defined in this module

      MT  TypeDef Name
------------------------------------------------------------------------------
011737b8 0x02000003 WindbugDemo.MemoryGen

Types referenced in this module

      MT    TypeRef Name
------------------------------------------------------------------------------
682e41b8 0x02000001 System.Object
0:000> !dumpmt -md 011737b8 
EEClass:         011712d4
Module:          01172edc
Name:            WindbugDemo.MemoryGen
mdToken:         02000003
File:            D:\bin\MemoryGen.exe
BaseSize:        0xc
ComponentSize:   0x0
Slots in VTable: 6
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
   Entry MethodDe    JIT Name
681c952c 67ee612c PreJIT System.Object.ToString()
681dec30 67ee6134 PreJIT System.Object.Equals(System.Object)
681de860 67ee6154 PreJIT System.Object.GetHashCode()
681de2a0 67ee6168 PreJIT System.Object.Finalize()
0117c015 011737b0   NONE WindbugDemo.MemoryGen..ctor()
0117c011 011737a4   NONE WindbugDemo.MemoryGen.Main(System.String[])
0:000> !bpmd -md 011737a4   
MethodDesc = 011737a4
Adding pending breakpoints...
sxe -c "!HandleCLRN" clrn
0:000> g
(ad0.a2c): CLR notification exception - code e0444143 (first chance)
JITTED MemoryGen!WindbugDemo.MemoryGen.Main(System.String[])
Setting breakpoint: bp 011E0099 [WindbugDemo.MemoryGen.Main(System.String[])]
bp 011E0099
g
Breakpoint 0 hit
eax=00000000 ebx=001bf33c ecx=01602198 edx=00000000 esi=01602198 edi=001bf288
eip=011e0099 esp=001bf238 ebp=001bf298 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
011e0099 90              nop
0:000> !u 011737a4   
Normal JIT generated code
WindbugDemo.MemoryGen.Main(System.String[])
Begin 011e0050, size 1a9
*** WARNING: Unable to verify checksum for MemoryGen.exe

d:\source\03MemoryGen\MemoryGen.cs @ 42:
011e0050 55              push    ebp
011e0051 8bec            mov     ebp,esp
011e0053 57              push    edi
011e0054 56              push    esi
011e0055 83ec58          sub     esp,58h
...
d:\source\03MemoryGen\MemoryGen.cs @ 57:
011e01cd 33d2            xor     edx,edx
011e01cf 8955b8          mov     dword ptr [ebp-48h],edx

...
0:000> bp 011e01cd 
0:000> !bpmd mscorlib.dll System.GC.Collect
Found 4 methods in module 67ee1000...
MethodDesc = 67f709ec
MethodDesc = 67f709f8
MethodDesc = 67f70a04
MethodDesc = 67f70a10
Setting breakpoint: bp 681BEF6C [System.GC.Collect(Int32, System.GCCollectionMode, Boolean)]
bp 681BEF6C
Setting breakpoint: bp 688A5B80 [System.GC.Collect(Int32, System.GCCollectionMode)]
bp 688A5B80
Setting breakpoint: bp 688A5B2D [System.GC.Collect()]
bp 688A5B2D
Setting breakpoint: bp 688A5B10 [System.GC.Collect(Int32)]
bp 688A5B10
Adding pending breakpoints...
sxe -c "!HandleCLRN" clrn
0:000> g

4、在【release = null;】的这句代码加上断点,对象赋空后,GC操作后,我们可以再查阅一个该对象的引用。!bpmd mscorlib.dll System.GC.Collect命令,表示当我们显式调用GC.Collect时,Windbg能中止程序,进入调试命令。

5、当程序中断时,调用!clrstack -a命令,观察一下是否是由于大对象(>90)这个if分支引起的中断,否则我们就执行dumpgen(需要加载sosex.dll调试扩展)

0:000> !clrstack -a
OS Thread Id: 0xa2c (0)
Child SP       IP Call Site
001bf208 688a5b2d System.GC.Collect()

001bf20c 011e01d8 [InlinedCallFrame: 001bf20c] 
001bf238 011e01d8 WindbugDemo.MemoryGen.Main(System.String[]) [d:\source\03MemoryGen\MemoryGen.cs @ 59]
    PARAMETERS:
        args (0x001bf28c) = 0x01602198
    LOCALS:
        0x001bf25c = 0x016021a8
        0x001bf258 = 0x016021d8
        0x001bf288 = 0x00000064
        0x001bf254 = 0x01624ab0
        0x001bf250 = 0x016022d8
        0x001bf280 = 0x65280834
        0x001bf27c = 0x00000001
0:000> !do 0x016022d8
Name:        WindbugDemo.MemoryApply
MethodTable: 011745e8
EEClass:     01171360
Size:        24(0x18) bytes
File:        D:\bin\MemoryGen.exe
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
682e6d34  4000001        c        System.Byte[]  0 instance 016022f0 AllocateByte
682f05f4  4000002        4         System.Int64  1 instance 637300683725008226 <Ticks>k__BackingField
682e560c  4000003       10         System.Int32  1 instance       69 <MemSize>k__BackingField

0:000> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x01601018
generation 1 starts at 0x0160100c
generation 2 starts at 0x01601000
ephemeral segment allocation context: (0x01624c54, 0x01625bf4)
         segment             begin         allocated  size
01600000  01601000  01625bf4  0x24bf4(150516)
Large object heap starts at 0x02601000
         segment             begin         allocated  size
02600000  02601000  0261da58  0x1ca58(117336)
Total Size:              Size: 0x4164c (267852) bytes.
------------------------------
GC Heap Size:    Size: 0x4164c (267852) bytes.
0:000> .load sosex.dll
0:000> !dumpgen 0 -type WindbugDemo.MemoryApply
Object     MT            Size   Name
---------------------------------------------------
016021a8   01174638        32   System.Collections.Generic.Queue`1[[WindbugDemo.MemoryApply, MemoryGen]]
016022d8   011745e8        24   WindbugDemo.MemoryApply
01615abc   011745e8        24   WindbugDemo.MemoryApply
01624ab0   011745e8        24   WindbugDemo.MemoryApply
4 objects, 104 bytes
0:000> !dumpgen 1 -type WindbugDemo.MemoryApply
0 objects, 0 bytes
0:000> !dumpgen 2 -type WindbugDemo.MemoryApply
0 objects, 0 bytes
0:000> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x01601018
generation 1 starts at 0x0160100c
generation 2 starts at 0x01601000
ephemeral segment allocation context: (0x01624c54, 0x01625bf4)
         segment             begin         allocated  size
01600000  01601000  01625bf4  0x24bf4(150516)
Large object heap starts at 0x02601000
         segment             begin         allocated  size
02600000  02601000  0261da58  0x1ca58(117336)
Total Size:              Size: 0x4164c (267852) bytes.
------------------------------
GC Heap Size:    Size: 0x4164c (267852) bytes.

运行 !do命令,观察0x01601018对象,跟eeheap命令输出的内存段相比,的确位于0代内存上。用!dumpgen 0 -type WindbugDemo.MemoryApply命令,输出结果也验证了我们的猜想。

6、运行g命令,再次启动程序。

0:000> g
Breakpoint 4 hit
eax=001bf418 ebx=001bf33c ecx=01615abc edx=00000000 esi=0036d090 edi=001bf20c
eip=688a5b2d esp=001bf208 ebp=001bf230 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
mscorlib_ni+0x9c5b2d:
688a5b2d 6a02            push    2
0:000> !clrstack -a
OS Thread Id: 0xa2c (0)
Child SP       IP Call Site
001bf208 688a5b2d System.GC.Collect()

001bf20c 011e01d8 [InlinedCallFrame: 001bf20c] 
001bf238 011e01d8 WindbugDemo.MemoryGen.Main(System.String[]) [d:\source\03MemoryGen\MemoryGen.cs @ 59]
    PARAMETERS:
        args (0x001bf28c) = 0x01602198
    LOCALS:
        0x001bf25c = 0x016021a8
        0x001bf258 = 0x016021d8
        0x001bf288 = 0x00000043
        0x001bf254 = 0x01624be0
        0x001bf250 = 0x01615abc
        0x001bf280 = 0x13c9dc2e
        0x001bf27c = 0x00000001

001bf418 68f52552 [GCFrame: 001bf418] 
0:000> !dumpgen 0 -type WindbugDemo.MemoryApply
Object     MT            Size   Name
---------------------------------------------------
01624be0   011745e8        24   WindbugDemo.MemoryApply
1 object, 24 bytes
0:000> !dumpgen 1 -type WindbugDemo.MemoryApply
Object     MT            Size   Name
---------------------------------------------------
016021a8   01174638        32   System.Collections.Generic.Queue`1[[WindbugDemo.MemoryApply, MemoryGen]]
016022d8   011745e8        24   WindbugDemo.MemoryApply
01615abc   011745e8        24   WindbugDemo.MemoryApply
01624ab0   011745e8        24   WindbugDemo.MemoryApply
4 objects, 104 bytes
0:000> !dumpgen 2 -type WindbugDemo.MemoryApply
0 objects, 0 bytes

我们发现原来位于0代的内存对象,已经被系统提升至了1代。而2代内存对象没有。

7、运行g命令,让程序继续执行,当程序再次中断时

0:000> g
Breakpoint 1 hit
eax=00000001 ebx=001bf33c ecx=016159b8 edx=00000000 esi=001bf270 edi=001bf280
eip=011e01cd esp=001bf238 ebp=001bf298 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
011e01cd 33d2            xor     edx,edx
0:000> !clrstack -a
OS Thread Id: 0xa2c (0)
Child SP       IP Call Site
001bf238 011e01cd WindbugDemo.MemoryGen.Main(System.String[]) [d:\source\03MemoryGen\MemoryGen.cs @ 57]
    PARAMETERS:
        args (0x001bf28c) = 0x01602198
    LOCALS:
        0x001bf25c = 0x016021a8
        0x001bf258 = 0x016021d8
        0x001bf288 = 0x00000073
        0x001bf254 = 0x016352d4
        0x001bf250 = 0x01624ab0
        0x001bf280 = 0x387ad227
        0x001bf27c = 0x00000000

001bf418 68f52552 [GCFrame: 001bf418] 
0:000> !do 0x387ad227
<Note: this object has an invalid CLASS field>
Invalid object
0:000> !do 0x01624ab0
Name:        WindbugDemo.MemoryApply
MethodTable: 011745e8
EEClass:     01171360
Size:        24(0x18) bytes
File:        D:\bin\MemoryGen.exe
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
682e6d34  4000001        c        System.Byte[]  0 instance 026053a8 AllocateByte
682f05f4  4000002        4         System.Int64  1 instance 637300683735304244 <Ticks>k__BackingField
682e560c  4000003       10         System.Int32  1 instance      100 <MemSize>k__BackingField
0:000> !gcroot 0x01624ab0
Thread a2c:
    001bf238 011e01cd WindbugDemo.MemoryGen.Main(System.String[]) [d:\source\03MemoryGen\MemoryGen.cs @ 57]
        ebp+48: 001bf250
            ->  01624ab0 WindbugDemo.MemoryApply

    001bf238 011e01cd WindbugDemo.MemoryGen.Main(System.String[]) [d:\source\03MemoryGen\MemoryGen.cs @ 57]
        ebp+5c: 001bf23c
            ->  01624ab0 WindbugDemo.MemoryApply

Found 2 unique roots (run !GCRoot -all to see all roots).

这时,我们发现,是因为出队的这个对象尺寸大于90K,那么对象会被置为空,查看GCroot,这时的对象尚未被回收,我们继续运行g命令。

0:000> g
Breakpoint 4 hit
eax=001bf418 ebx=001bf33c ecx=01624be0 edx=00000000 esi=0036d090 edi=001bf20c
eip=688a5b2d esp=001bf208 ebp=001bf230 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
mscorlib_ni+0x9c5b2d:
688a5b2d 6a02            push    2
0:000> !clrstack -a
OS Thread Id: 0xa2c (0)
Child SP       IP Call Site
001bf208 688a5b2d System.GC.Collect()

001bf20c 011e01d8 [InlinedCallFrame: 001bf20c] 
001bf238 011e01d8 WindbugDemo.MemoryGen.Main(System.String[]) [d:\source\03MemoryGen\MemoryGen.cs @ 59]
    PARAMETERS:
        args (0x001bf28c) = 0x01602198
    LOCALS:
        0x001bf25c = 0x016021a8
        0x001bf258 = 0x016021d8
        0x001bf288 = 0x00000056
        0x001bf254 = 0x016355cc
        0x001bf250 = 0x01624be0
        0x001bf280 = 0x1abedf72
        0x001bf27c = 0x00000001

001bf418 68f52552 [GCFrame: 001bf418] 
0:000> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x016355c0
generation 1 starts at 0x016351bc
generation 2 starts at 0x01601000
ephemeral segment allocation context: (0x0163576c, 0x016375cc)
         segment             begin         allocated  size
01600000  01601000  016375cc  0x365cc(222668)
Large object heap starts at 0x02601000
         segment             begin         allocated  size
02600000  02601000  0264ebc0  0x4dbc0(318400)
Total Size:              Size: 0x8418c (541068) bytes.
------------------------------
GC Heap Size:    Size: 0x8418c (541068) bytes.
0:000> !do 0x01624ab0
Name:        WindbugDemo.MemoryApply
MethodTable: 011745e8
EEClass:     01171360
Size:        24(0x18) bytes
File:        D:\bin\MemoryGen.exe
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
682e6d34  4000001        c        System.Byte[]  0 instance 026053a8 AllocateByte
682f05f4  4000002        4         System.Int64  1 instance 637300683735304244 <Ticks>k__BackingField
682e560c  4000003       10         System.Int32  1 instance      100 <MemSize>k__BackingField
0:000> !FinalizeQueue
SyncBlocks to be cleaned up: 0
Free-Threaded Interfaces to be released: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 0 finalizable objects (00376d20->00376d20)
generation 1 has 0 finalizable objects (00376d20->00376d20)
generation 2 has 6 finalizable objects (00376d08->00376d20)
Ready for finalization 0 objects (00376d20->00376d20)
Statistics for all finalizable objects (including all objects ready for finalization):
      MT    Count    TotalSize Class Name
682e7048        1           20 Microsoft.Win32.SafeHandles.SafePEFileHandle
682e6068        1           20 Microsoft.Win32.SafeHandles.SafeFileHandle
682dc234        1           20 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
682dc1e4        1           20 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle
682e76d0        1           44 System.Threading.ReaderWriterLock
682e4960        1           52 System.Threading.Thread
Total 6 objects
0:000> !gcroot 0x01624ab0
Found 0 unique roots (run ‘!GCRoot -all‘ to see all roots).
0:000> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x016355c0
generation 1 starts at 0x016351bc
generation 2 starts at 0x01601000
ephemeral segment allocation context: (0x0163576c, 0x016375cc)
         segment             begin         allocated  size
01600000  01601000  016375cc  0x365cc(222668)
Large object heap starts at 0x02601000
         segment             begin         allocated  size
02600000  02601000  0264ebc0  0x4dbc0(318400)
Total Size:              Size: 0x8418c (541068) bytes.
------------------------------
GC Heap Size:    Size: 0x8418c (541068) bytes.
0:000> !dumpgen 0 -type WindbugDemo.MemoryApply
Object     MT            Size   Name
---------------------------------------------------
016355cc   011745e8        24   WindbugDemo.MemoryApply
1 object, 24 bytes
0:000> !dumpgen 1 -type WindbugDemo.MemoryApply
Object     MT            Size   Name
---------------------------------------------------
016352d4   011745e8        24   WindbugDemo.MemoryApply
1 object, 24 bytes
0:000> !dumpgen 2 -type WindbugDemo.MemoryApply
Object     MT            Size   Name
---------------------------------------------------
016021a8   01174638        32   System.Collections.Generic.Queue`1[[WindbugDemo.MemoryApply, MemoryGen]]
01624ab0   011745e8        24   WindbugDemo.MemoryApply
01624be0   011745e8        24   WindbugDemo.MemoryApply
3 objects, 80 bytes
0:000> .logclose
Closing open log file d:\log\mem11.txt

 这时,我们发现原来的1代内存已经被提升至第2代了。

Windbg探索之.NET内存管理方式

标签:内存分配   address   jit   shc   ram   null   apply   reading   编译   

人气教程排行