For more high-quality dry goods: See my GitHub:dotnetfly

A: background

1. Tell a story

To be honest, I was not prepared to interpret this dump in the last article, but it has two points that deeply moved me.

  1. I’ve heard so many times that you can do game development with Unity, but seeing is believing.

  2. There are a lot of jin Yong wuxia novel names in the game, it is very pleasing to the eye.


000000df315978a8    0          3Jade bone fan000000df31597cd8    0          3Yunlong gun000000df31596d88    0          3Evil wind claw000000df315967a8    0          4The snow chain of silk000000df31596ad0    0          4B wooden excalibur000000df31596040    0          3Star yao crown000000df31595328    0          3Sharply hammer...Copy the code

So with such a good dump, I have to leave something for it.

Anyway, this fate started last month when a friend said that its program virtual memory occupation is very large, and asked how to solve it, as shown below:

Dump: Dump: dump: dump: dump: dump: dump: dump: dump: dump: dump

Two: Windbg analysis

1. Where exactly is the leak

Analyze the memory problem and, again, split it in two to see which area (managed or unmanaged) is leaking.

First take a look at the total process memory, use! Address-summary command.


0:087> !address -summary

--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free                                    458     7ffe`9e6a8000 ( 127.995 TB)          100.00%
Heap                                  48514        1`005fd000 (   4.006 GB)  72.51%    0.00%
<unknown>                              2504        0`2c6ad000 ( 710.676 MB)  12.56%    0.00%
Stack                                   504        0`2a000000 ( 672.000 MB)  11.88%    0.00%
Image                                   410        0`0a971000 ( 169.441 MB)   3.00%    0.00%
Other                                    18        0`001dc000 (   1.859 MB)   0.03%    0.00%
TEB                                     168        0`00150000 (   1.312 MB)   0.02%    0.00%
PEB                                       1        0`00001000 (   4.000 kB)   0.00%    0.00% -- -- --Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_PRIVATE                           51581        1`5130f000 (   5.269 GB) 95.36% 0.00% MEM_IMAGE 416 0 '0aa6b000 ( 170.418 MB) 3.01% 0.00% MEM_MAPPED 122 0 '05bce000 (  91.805 MB) 1.62% 0.00% - State Summary -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- RgnCount -- -- -- -- -- -- -- -- -- -- - the Total Size -- -- -- -- -- -- -- -- % % ofBusy ofTotal MEM_FREE 458 7ffe`9e6a8000 ( 127.995 TB) 100.00% MEM_COMMIT 51465 1 '1c741000 (   4.445 GB) 80.45% 0.00% MEM_RESERVE 654 0 '45207000 (   1.080 GB)  19.55%    0.00%

Copy the code

MEM_COMMIT= 4.4g MEM_COMMIT= 4.4g Eeheap-gc command.


0:087> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x000000df3118dc48
generation 1 starts at 0x000000df3118b098
generation 2 starts at 0x000000df30fc1000
ephemeral segment allocation context: none
         segment             begin         allocated              size
000000df30fc0000  000000df30fc1000  000000df3178cae0  0x7cbae0(8174304)
Large object heap starts at 0x000000df40fc1000
         segment             begin         allocated              size
000000df40fc0000  000000df40fc1000  000000df410637b8  0xa27b8(665528)
Total Size:              Size: 0x86e298 (8839832) bytes.
------------------------------
GC Heap Size:            Size: 0x86e298 (8839832) bytes.


Copy the code

GC Heap Size= 8839832 Byte = 8M 🤣🤣🤣🤣, obviously this is an unmanaged memory leak, since the direction is determined, then check the unmanaged area!

2. Explore unmanaged leaks

According to experience, to find unmanaged leakage, first look at the loader heap, many programs are often caused by the dynamic creation of too many assemblies, such as the classic Castle, XmlSerializer, interested friends can find this information online, here use! View the eeheap-loader command.


0:087> !eeheap -loader

--------------------------------------
Jit code heap:
LoaderCodeHeap:    0000000000000000(0:0) Size: 0x0 (0) bytes.
Total size:        Size: 0x0 (0) bytes.
--------------------------------------
Module Thunk heaps:
Module 00007ffda5fa1000: Size: 0x0 (0) bytes.
Module 00007ffd485c4148: Size: 0x0 (0) bytes.
Module 00007ffda2631000: Size: 0x0 (0) bytes.
Module 00007ffda5331000: Size: 0x0 (0) bytes.
Module 00007ffdac621000: Size: 0x0 (0) bytes.
Module 00007ffdac4e1000: Size: 0x0 (0) bytes.
Module 00007ffda48b1000: Size: 0x0 (0) bytes.
Module 00007ffda1791000: Size: 0x0 (0) bytes.
Module 00007ffd487b1858: Size: 0x0 (0) bytes.
Total size:              Size: 0x0 (0) bytes.
--------------------------------------
Module Lookup Table heaps:
Module 00007ffda5fa1000: Size: 0x0 (0) bytes.
Module 00007ffd485c4148: Size: 0x0 (0) bytes.
Module 00007ffda2631000: Size: 0x0 (0) bytes.
Module 00007ffda5331000: Size: 0x0 (0) bytes.
Module 00007ffdac621000: Size: 0x0 (0) bytes.
Module 00007ffdac4e1000: Size: 0x0 (0) bytes.
Module 00007ffda48b1000: Size: 0x0 (0) bytes.
Module 00007ffda1791000: Size: 0x0 (0) bytes.
Module 00007ffd487b1858: Size: 0x0 (0) bytes.
Total size:              Size: 0x0 (0) bytes.
--------------------------------------
Total LoaderHeap size:   Size: 0x99000 (626688) bytes total, 0x2000 (8192) bytes wasted.
=======================================

Copy the code

Total heap size= 626K Total heap size= 626K The heap -s command.


0:087>! heap -s * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  NT HEAP STATS BELOW * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  LFH Key :0xb6c37b3e3a4a189e
Termination on corruption : ENABLED
          Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast 
                            (k)     (k)    (k)     (k) length blocks cont. heap ------------------------------------------------------------------------------------- 000000df2e680000 00000002 4145084 4130108 4144304 1537 775 260 1 4 LFH 000000df2e1f0000 00008000 64 4 64 2 1 1 0 0 000000df2e830000 00001002 1860 172 1080 15 5 2 0 0 LFH 000000df2ec80000 00001002 1860 236 1080 5 7 2 0 0 LFH 000000df309e0000 00001002 60 8 60 2 1 1 0 0 000000df30bb0000 00041002 60 8 60 5 1 1 0 0 000000df49bd0000 00001002 840 44  60 3 3 1 0 0 LFH 000000df49b20000 00041002 1860 96 1080 8 3 2 0 0 LFH 000000df30b40000 00001002 60 20 60 9 2 1 0 0 000000df30b30000 00001002 1860 152 1080 11 8 2 0 0 LFH 000000df4bbb0000 00001002 3904 1292 3124 49 6 3 0 0 LFH 000000df89920000 00001002 1860 372 1080 14 7 2 0 0 LFH 000000df89be0000 00001006 1860 280 1080 23 2 2 0 0 LFH 000000df56f40000 00001006 32372 26204 31592 1434 21 6 0 6b LFH 000000df56f10000 00001006 1860 176 1080 21 3 2 0 0 LFH 000000df89ac0000 00001006 3904 2160 3124 67 4 3 0 2e LFH -------------------------------------------------------------------------------------Copy the code

Heap = 000000DF2e680000; heap= 000000DF2e680000; heap= 000000DF2e680000; The heap-stat -h 000000df2e680000 command displays heap statistics.


0:087>  !ext.heap -stat -h 000000df2e680000
 heap @ 000000df2e680000
group-by: TOTSIZE max-display: 20
    size     #blocks total ( %) (percent of total busy bytes)
    2000 4cfd2 - 99fa4000  (68.76)
    58 9d7492 - 36201230  (24.17)
    12c 267e8 - 2d1c3e0  (1.26)
    21d1 c46 - 19f0b26  (0.72)
    4020 634 - 18dc680  (0.69)
    a0 26d00 - 1842000  (0.68)
    a 1d3ebb - 124734e  (0.51)
    10 f8d99 - f8d990  (0.43)
    6 16adae - 881214  (0.24)
    b b3508 - 7b4758  (0.22)
    7 115125 - 793803  (0.21)
    5 17b833 - 7698ff  (0.21)
    c 86027 - 6481d4  (0.18)
    9 afef9 - 62f6c1  (0.17)
    d 6a80f - 5688c3  (0.15)
    f 4f5a9 - 4a64e7  (0.13)
    e 54814 - 49f118  (0.13)
    8 8b092 - 458490  (0.12)
    13 3139b - 3a7481  (0.10)
    15 25d06 - 31a17e  (0.09)

Copy the code

The heap was filled by size=2000 and size=58. The heap was filled by size=2000 and size=58. The heap was filled by size=2000 and size=58. Heap-flt s 2000 Finds the first address of all these blocks in the heap.


0:087>  !ext.heap -flt s 2000
    _HEAP @ df2e680000
              HEAP_ENTRY Size Prev Flags            UserPtr UserSize - state
        000000df2e702dd0 0201 0000  [00]   000000df2e702de0    02000 - (busy)
        000000df2e72c7e0 0201 0201  [00]   000000df2e72c7f0    02000 - (busy)
        000000df517400c0 0201 0201  [00]   000000df517400d0    02000 - (busy)
        000000df517420d0 0201 0201  [00]   000000df517420e0    02000 - (busy)
        000000df517440e0 0201 0201  [00]   000000df517440f0    02000 - (busy)
        000000df517460f0 0201 0201  [00]   000000df51746100    02000 - (busy)
        000000df51748100 0201 0201  [00]   000000df51748110    02000 - (busy)
        000000df5174a110 0201 0201  [00]   000000df5174a120    02000 - (busy)
        000000df5174c120 0201 0201  [00]   000000df5174c130    02000 - (busy)
        000000df5174e130 0201 0201  [00]   000000df5174e140    02000 - (busy)
        000000df51750140 0201 0201  [00]   000000df51750150    02000 - (busy)
        ...
Copy the code

The above HEAP_ENTRY is the first address of the block. Since there are approximately 4cfd2= 31.5W such blocks, it is impossible to list them one by one. The next step is to use DC to observe the contents of the memory blocks of these blocks to find the rules. Still have to use the script, here again take the first 100 thousand view.


function show_all_blocksize() {

    var output = exec(! "" ext.heap -flt s 58").Take(10000);
    for (var line of output) {

        var heap_entry_address = line.trim().split(' ') [0];

        if (heap_entry_address.indexOf("00") = =- 1) continue; show_heap_entry(heap_entry_address); }}function show_heap_entry(heap_entry_address) {

    var pageIndex = (index++);

    var path = ".writemem D:\\file\\"+ pageIndex + ".txt " + heap_entry_address + " L? 0x58";

    var output = exec(path);

    log("pageIndex=" + pageIndex);
}

Copy the code

After executing the script generation to TXT, the screenshot is as follows:

Observing that there is a lot of user information in the heap, and then using that information to identify friends.

After a brief conversation with a friend, that’s all I can do. Case closed.

Three:

The cause of this accident is due to C# call Lua, Lua did not make a reasonable memory release caused by unmanaged leakage, specific how to release in the code layer, this is up to my friend luck.

Finally, a small egg, friends are too polite.

Never seen such a big red envelope, I unexpectedly received 🤣🤣🤣, backhanded to the company’s r & D partners a cup of afternoon tea, here to say thank you to our friends, 😘 college