操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    :背景

    1. 講故事

    前段時間有個朋友找到我,說他們的程序有偶發崩潰的情況,讓我幫忙看下怎么回事,針對這種 crash 的程序,用 AEDebug 的方式抓取一個便知,有了 dump 之后接下來就可以分析了。

    二:Windbg 分析

    1. 為什么會崩潰

    既然是程序的崩潰,我們可以像看藍屏一下看dump文件,使用 !analyze -v 命令即可。

    
    0:000> !analyze -v
    *******************************************************************************
    *                                                                             *
    *                        Exception Analysis                                   *
    *                                                                             *
    *******************************************************************************
    CONTEXT:  (.ecxr)
    rax=0000000000000000 rbx=0000000000f7ccb0 rcx=00007ffe23af7ab0
    rdx=00000000013e3b10 rsi=0000000000f7ccb0 rdi=0000000000f7c7c0
    rip=00007ffe538e7044 rsp=0000000000f7cf60 rbp=0000000000f7d770
     r8=0000000000000001  r9=000000f7000006bd r10=0000000000f7d640
    r11=0000000000f7cf50 r12=0000000000000001 r13=0000000000000001
    r14=000000005c520126 r15=00000000013e3b10
    iopl=0         nv up ei pl nz na po nc
    cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010204
    clr!ComPreStubWorker+0xf2e54:
    00007ffe`538e7044 f6403820        test    byte ptr [rax+38h],20h ds:00000000`00000038=??
    Resetting default scope
    
    EXCEPTION_RECORD:  (.exr -1)
    ExceptionAddress: 00007ffe538e7044 (clr!ComPreStubWorker+0x00000000000f2e54)
       ExceptionCode: c0000005 (Access violation)
      ExceptionFlags: 00000001
    NumberParameters: 2
       Parameter[0]: 0000000000000000
       Parameter[1]: 0000000000000038
    Attempt to read from address 0000000000000038
    
    PROCESS_NAME:  xxx.exe
    
    READ_ADDRESS:  0000000000000038 
    
    ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%p            0x%p                    %s
    
    EXCEPTION_CODE_STR:  c0000005
    
    EXCEPTION_PARAMETER1:  0000000000000000
    
    EXCEPTION_PARAMETER2:  0000000000000038
    
    STACK_TEXT:  
    00000000`00f7cf60 00007ffe`538e7044 clr!ComPreStubWorker+0xf2e54
    00000000`00f7d590 00007ffe`53712d62 clr!ComCallPreStub+0x62
    00000000`00f7d660 00007ffe`1de3ba83 wwkrn64+0xba83
    00000000`00f7d740 00007ffe`638ebc70 ole32!CPrivDragDrop::PrivDragDrop+0x2b0
    00000000`00f7d790 00007ffe`638eb98c ole32!PrivDragDrop+0x198
    00000000`00f7d830 00007ffe`638a9c1e ole32!CDragOperation::GetDropTarget+0xee
    00000000`00f7d8b0 00007ffe`638ac239 ole32!CDragOperation::UpdateTarget+0x4cd
    ....
    
    

    從上面的信息看,這個程序是一個經典的 訪問違例 異常,違例是因為 rax=0 導致讀取了不該讀取的地方,接下來我們切到異常上下文看下為什么會是 0 ?

    2. eax 為什么會是 0

    要想切到異常上下文,先使用 .ecxr 命令,再使用 ub 反匯編。

    
    0:000> .ecxr
    rax=0000000000000000 rbx=0000000000f7ccb0 rcx=00007ffe23af7ab0
    rdx=00000000013e3b10 rsi=0000000000f7ccb0 rdi=0000000000f7c7c0
    rip=00007ffe538e7044 rsp=0000000000f7cf60 rbp=0000000000f7d770
     r8=0000000000000001  r9=000000f7000006bd r10=0000000000f7d640
    r11=0000000000f7cf50 r12=0000000000000001 r13=0000000000000001
    r14=000000005c520126 r15=00000000013e3b10
    iopl=0         nv up ei pl nz na po nc
    cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010204
    clr!ComPreStubWorker+0xf2e54:
    00007ffe`538e7044 f6403820        test    byte ptr [rax+38h],20h ds:00000000`00000038=??
    
    0:000> ub 00007ffe`538e7044
    clr!ComPreStubWorker+0xf2e20:
    00007ffe`538e7010 0f8591d3f0ff    jne     clr!ComPreStubWorker+0x1b4 (00007ffe`537f43a7)
    00007ffe`538e7016 488b0e          mov     rcx,qword ptr [rsi]
    00007ffe`538e7019 488d81b8ffffff  lea     rax,[rcx-48h]
    00007ffe`538e7020 48898424c0050000 mov     qword ptr [rsp+5C0h],rax
    00007ffe`538e7028 48898424b8050000 mov     qword ptr [rsp+5B8h],rax
    00007ffe`538e7030 488b89c0ffffff  mov     rcx,qword ptr [rcx-40h]
    00007ffe`538e7037 e8fcfcebff      call    clr!MethodTable::GetComCallWrapperTemplate (00007ffe`537a6d38)
    00007ffe`538e703c 48898424b0050000 mov     qword ptr [rsp+5B0h],rax
    
    

    從匯編代碼看,rax 是 clr!MethodTable::GetComCallWrapperTemplate 方法的返回值,從方法名字看是一個經典的 COM 和 .NET 互操作,接下來繼續用 uf 反匯編看下這個方法,精簡后的代碼如下:

    
    0:000> uf clr!MethodTable::GetComCallWrapperTemplate
    00007ffe`537a6d38 48895c2408      mov     qword ptr [rsp+8],rbx
    00007ffe`537a6d3d 57              push    rdi
    ...
    00007ffe`537a6d57 488bcb          mov     rcx,rbx
    00007ffe`537a6d5a e8c943f7ff      call    clr!MethodTable::GetClass (00007ffe`5371b128)
    00007ffe`537a6d5f 488b4030        mov     rax,qword ptr [rax+30h]
    ...
    
    

    再結合 coreclr 源碼:

    
    inline ComCallWrapperTemplate *MethodTable::GetComCallWrapperTemplate()
    {
        LIMITED_METHOD_CONTRACT;
        return GetClass()->GetComCallWrapperTemplate();
    }
    
    class EEClass // DO NOT CREATE A NEW EEClass USING NEW!
    {
        ComCallWrapperTemplate* m_pccwTemplate;   // points to interop data structures used when this type is exposed to COM
    
        inline ComCallWrapperTemplate *GetComCallWrapperTemplate()
        {
            LIMITED_METHOD_CONTRACT;
            return m_pccwTemplate;
        }
    }
    
    

    到這里大概能推測到是因為 EEClass.m_pccwTemplate 字段為 null 所致,從注釋看,他是 CLR 用來暴露給 COM 使用的數據結構,那為什么暴露給 COM 使用的數據結構為 NULL 呢? 這個分析起來就復雜了。

    但有一點可以確定,像這種邏輯必然是 堅如磐石,受過日月精華,經歷過500年的風吹雨打,不可能無緣無故的出簍子。

    3. 出路在哪里

    要尋找突破口還得從調用棧入手,我們用 k 命令洞察一下。

    
    0:000> k
      *** Stack trace for last set context - .thread/.cxr resets it
     # Child-SP          RetAddr               Call Site
    00 00000000`00f7cf60 00007ffe`53712d62     clr!ComPreStubWorker+0xf2e54
    01 00000000`00f7d590 00007ffe`1de3ba83     clr!ComCallPreStub+0x62
    02 00000000`00f7d660 00007ffe`638ebc70     wwkrn64+0xba83
    03 00000000`00f7d740 00007ffe`638eb98c     ole32!CPrivDragDrop::PrivDragDrop+0x2b0 [com\ole32\com\rot\getif.cxx @ 659] 
    04 00000000`00f7d790 00007ffe`638a9c1e     ole32!PrivDragDrop+0x198 [com\ole32\com\rot\getif.cxx @ 920] 
    05 00000000`00f7d830 00007ffe`638ac239     ole32!CDragOperation::GetDropTarget+0xee [com\ole32\ole232\drag\drag.cpp @ 1128] 
    06 00000000`00f7d8b0 00007ffe`638ac91c     ole32!CDragOperation::UpdateTarget+0x4cd [com\ole32\ole232\drag\drag.cpp @ 2026] 
    07 00000000`00f7d9a0 00007ffe`2443f664     ole32!DoDragDrop+0x10c [com\ole32\ole232\drag\drag.cpp @ 3007] 
    08 00000000`00f7dc80 00007ffe`244ccd8d     System_Windows_Forms_ni+0x9cf664
    ...
    
    

    仔細觀察線程棧信息,不難發現用戶是在用 DoDragDrop 方法實現控件的拖拽,不過在執行流中有一個陌生的動態鏈接庫 wwkrn64,它到底是何方神圣呢?我們用 lmvm 觀察下。

    
    0:000> lmvm wwkrn64
    Browse full module list
    start             end                 module name
    00007ffe`1de30000 00007ffe`1df1e000   wwkrn64  C (export symbols)       wwkrn64.dll
        Loaded symbol image file: wwkrn64.dll
        Image path: D:\xxx\wwall\wwkrn64.dll
        Image name: wwkrn64.dll
        Browse all global symbols  functions  data
        Timestamp:        Wed Apr 26 10:18:26 2023 (644889F2)
        CheckSum:         00000000
        ImageSize:        000EE000
        Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4
        Information from resource tables:
    
    

    從輸出信息看,果然是一個外來物種,經過網上一頓搜索,發現是一款 信息安全軟件,哪家公司就模糊了哈,截圖如下:

    到這里就真相大白了,讓朋友把這款軟件卸載掉再試試看,問題就解決了。

    4. 安全軟件為什么要介入

    我這里只能簡單推測一下,ComCallPreStub 和 ComPreStubWorker 方法是 JIT 在編譯某一個方法時的前綴路徑,也是很多 加殼軟件 以及 永恒之藍 這樣的蠕蟲病毒重點關注的方法,所以這些高危方法自然也是 安全軟件 重點監視的,如果 安全軟件 沒處理好,自然就會誤殺。。。

    當然真正的原因只能問 系鈴人 。

    可能有些朋友要說了,怎么驗證這兩個方法就是 JIT 編譯的前綴,這里我們用 普通方法+windbg 的方法簡單驗證下吧,參考代碼如下:

    
        internal class Program
        {
            static void Main(string[] args)
            {
                Debugger.Break();
                Test();
                Console.ReadLine();
            }
    
            static void Test()
            {
                Console.WriteLine("Test1");
            }
        }
    
    

    接下來我們重點觀察下 Test 方法的編譯過程,看過程之前先上一張架構圖:

    從架構圖看 Test() 方法的編譯最終是由 clrjit!jitNativeCode 來處理的,要想驗證很簡單用 bp clrjit!jitNativeCode 下一個斷點即可。

    
    0:000> bp clrjit!jitNativeCode
    0:000> g
    Breakpoint 0 hit
    clrjit!jitNativeCode:
    00007ffb`590cc040 4c894c2420      mov     qword ptr [rsp+20h],r9 ss:0000009c`5efed218=0000000000000000
    0:000> k
     # Child-SP          RetAddr               Call Site
    00 0000009c`5efed1f8 00007ffb`5917d683     clrjit!jitNativeCode [D:\a\_work\1\s\src\coreclr\jit\compiler.cpp @ 6941] 
    01 0000009c`5efed200 00007ffb`594d3091     clrjit!CILJit::compileMethod+0x83 [D:\a\_work\1\s\src\coreclr\jit\ee_il_dll.cpp @ 279] 
    02 (Inline Function) --------`--------     coreclr!invokeCompileMethodHelper+0x86 [D:\a\_work\1\s\src\coreclr\vm\jitinterface.cpp @ 12774] 
    03 (Inline Function) --------`--------     coreclr!invokeCompileMethod+0xc5 [D:\a\_work\1\s\src\coreclr\vm\jitinterface.cpp @ 12839] 
    04 0000009c`5efed270 00007ffb`594d274d     coreclr!UnsafeJitFunction+0x7f1 [D:\a\_work\1\s\src\coreclr\vm\jitinterface.cpp @ 13355] 
    05 0000009c`5efed760 00007ffb`594d22ce     coreclr!MethodDesc::JitCompileCodeLocked+0x1f1 [D:\a\_work\1\s\src\coreclr\vm\prestub.cpp @ 1051] 
    06 0000009c`5efed930 00007ffb`59472009     coreclr!MethodDesc::JitCompileCodeLockedEventWrapper+0x466 [D:\a\_work\1\s\src\coreclr\vm\prestub.cpp @ 920] 
    07 0000009c`5efeda90 00007ffb`59473f58     coreclr!MethodDesc::JitCompileCode+0x2a9 [D:\a\_work\1\s\src\coreclr\vm\prestub.cpp @ 860] 
    08 (Inline Function) --------`--------     coreclr!MethodDesc::PrepareILBasedCode+0x5ae [D:\a\_work\1\s\src\coreclr\vm\prestub.cpp @ 439] 
    09 (Inline Function) --------`--------     coreclr!MethodDesc::PrepareCode+0x5ae [D:\a\_work\1\s\src\coreclr\vm\prestub.cpp @ 332] 
    0a 0000009c`5efedb40 00007ffb`5947340c     coreclr!CodeVersionManager::PublishVersionableCodeIfNecessary+0x7f8 [D:\a\_work\1\s\src\coreclr\vm\codeversion.cpp @ 1701] 
    0b 0000009c`5efee070 00007ffb`5947316b     coreclr!MethodDesc::DoPrestub+0x16c [D:\a\_work\1\s\src\coreclr\vm\prestub.cpp @ 2215] 
    0c 0000009c`5efee190 00007ffb`595abec5     coreclr!PreStubWorker+0x21b [D:\a\_work\1\s\src\coreclr\vm\prestub.cpp @ 2039] 
    0d 0000009c`5efee320 00007ffa`f9a0296e     coreclr!ThePreStub+0x55
    0e 0000009c`5efee3d0 00007ffb`595aae93     Example_19_1_1!Example_19_1_1.Program.Main+0x2e [D:\skyfly\19.20230624\src\Example\Example_19_1_1\Program.cs @ 10] 
    ...
    
    

    如果想在 jitNativeCode 方法中把 md 提取出來的話,可以取 r9 參數。

    
    0:000> !dumpmd poi(r9)
    Method Name:          Example_19_1_1.Program.Test()
    Class:                00007ffaf9abd520
    MethodTable:          00007ffaf9ac8880
    mdToken:              0000000006000006
    Module:               00007ffaf9ac6908
    IsJitted:             no
    Current CodeAddr:     ffffffffffffffff
    Version History:
      ILCodeVersion:      0000000000000000
      ReJIT ID:           0
      IL Addr:            000001f865be20a7
         CodeAddr:           0000000000000000  (MinOptJitted)
         NativeCodeVersion:  0000000000000000
    
    

    三:總結

    這次崩潰事故的直接原因是由于第三方安全軟件的介入導致的,因 ComPreStubWorker 是加殼程序和蠕蟲病毒注入的突破口,不管怎樣還是希望安全軟件對高危函數 ComPreStubWorker 的照護邏輯再優化下吧,減少誤殺的發生。

    一:背景

    1. 講故事

    前段時間微信上有一位老朋友找到我,說他的程序跑著跑著內存會突然爆高,有時候會下去,有什么會下不去,懷疑是不是某些情況下存在內存泄露,讓我幫忙分析一下,其實內存泄露方面的問題還是比較好解決的,看過這個dump之后覺得還是有一定的分享價值,拿出來和大家分享一下吧。

    二:WinDbg 分析

    1. 托管還是非托管泄露

    這個首先是一定要確定的,否則就是南轅北轍,強調再多也不為過,可以用 !address -summary 觀察一下。

    
    0:000> !address -summary
    
    --- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
    Free                                    208     7ffb`691cd000 ( 127.982 TB)           99.99%
    <unknown>                               384        4`898d7000 (  18.149 GB)  98.87%    0.01%
    Image                                  1015        0`0b053000 ( 176.324 MB)   0.94%    0.00%
    Stack                                    90        0`01700000 (  23.000 MB)   0.12%    0.00%
    Heap                                     32        0`00bea000 (  11.914 MB)   0.06%    0.00%
    Other                                    14        0`001e0000 (   1.875 MB)   0.01%    0.00%
    TEB                                      23        0`0002e000 ( 184.000 kB)   0.00%    0.00%
    PEB                                       1        0`00001000 (   4.000 kB)   0.00%    0.00%
    
    --- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
    MEM_PRIVATE                             336        4`8ab0b000 (  18.167 GB)  98.96%    0.01%
    MEM_IMAGE                              1177        0`0b70f000 ( 183.059 MB)   0.97%    0.00%
    MEM_MAPPED                               46        0`00c09000 (  12.035 MB)   0.06%    0.00%
    
    --- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
    MEM_FREE                                208     7ffb`691cd000 ( 127.982 TB)           99.99%
    MEM_COMMIT                             1256        3`1f910000 (  12.493 GB)  68.05%    0.01%
    MEM_RESERVE                             303        1`77513000 (   5.864 GB)  31.95%    0.00%
    
    

    從卦中看,當前程序的提交內存占用了 12G,NTHEAP 占用了 11M,基本上就可以斷定這是一個托管內存的問題,看到這里還是非常開心的,由于托管層都帶有類型數據,分析起來非常簡單,接下來使用 !eeheap -gc 觀察下托管堆。

    
    0:000> !eeheap -gc
    Number of GC Heaps: 1
    generation 0 starts at 0x00000000e42f26c8
    generation 1 starts at 0x00000000e42e85a0
    generation 2 starts at 0x0000000001d71000
    ephemeral segment allocation context: none
             segment            begin         allocated             size
    0000000001d70000 0000000001d71000  0000000011961b98 0x000000000fbf0b98(264178584)
    000000005e540000 000000005e541000  000000006c2b6408 0x000000000dd75408(232215560)
    0000000247ff0000 0000000247ff1000  0000000252d751f8 0x000000000ad841f8(181944824)
    00000000e3ff0000 00000000e3ff1000  00000000f1e44850 0x000000000de53850(233125968)
    Large object heap starts at 0x0000000011d71000
             segment            begin         allocated             size
    0000000011d70000 0000000011d71000  0000000019d65098 0x0000000007ff4098(134168728)
    000000001dad0000 000000001dad1000  0000000025ac6fd0 0x0000000007ff5fd0(134176720)
    0000000028c50000 0000000028c51000  0000000030c318e8 0x0000000007fe08e8(134088936)
    0000000030c50000 0000000030c51000  0000000038c35518 0x0000000007fe4518(134104344)
    000000003e540000 000000003e541000  0000000046507ff0 0x0000000007fc6ff0(133984240)
    0000000046540000 0000000046541000  000000004e5296d0 0x0000000007fe86d0(134121168)
    000000004e540000 000000004e541000  000000005652af00 0x0000000007fe9f00(134127360)
    0000000056540000 0000000056541000  000000005e50b050 0x0000000007fca050(133996624)
    ...
    000000058fff0000 000000058fff1000  00000005d76c2910 0x00000000476d1910(1198332176)
    000000064e820000 000000064e821000  0000000695cbe808 0x000000004749d808(1196021768)
    000000013bff0000 000000013bff1000  00000001834c96d8 0x00000000474d86d8(1196263128)
    0000000257ff0000 0000000257ff1000  000000029f44e7e0 0x000000004745d7e0(1195759584)
    Total Size       0x2dbe1b140(12278935872)
    ------------------------------
    GC Heap Size       0x2dbe1b140(12278935872)
    
    

    從卦中看,托管堆占用了 12G 內存,而且都是被 LOH 給吃掉了,離真相越來越近了,接下來就是用 !dumpheap -stat 觀察下托管堆,看下到底是什么類型占的這么大?

    
    0:000> !dumpheap -stat
    total 477283 objects
    Statistics:
                  MT    Count    TotalSize Class Name
    0007ffeb28280b0     3516       365664 System.Reflection.RuntimeMethodInfo
    00007ffea909df50       62       728528 System.Data.RBTree`1+Node[[System.Data.DataRow, System.Data]][]
    00007ffeb285a610       14       804680 System.DateTime[]
    00007ffea909c5e8    17061      1637856 System.Data.DataRow
    00007ffeb2831180     1555      1978136 System.Int32[]
    00007ffeb282d430     1108      6648296 System.Int64[]
    00007ffeb2fce9d8       71     12821784 System.Decimal[]
    00007ffeb282a060   366739     15054680 System.String
    00007ffeb2817e50     7785     23534144 System.Object[]
    00000000009a2e60     4084   4772737632      Free
    00007ffeb28320a0    17400   7438877632 System.Byte[]
    ...
    
    

    從卦中看, System.Byte[] 數組只有 1.7W 個,居然占用了 7.4G 的內存,這說明有的 Byte[] 可能會非常大, 接下來就可以檢索 >10M 的數組排列情況,輸出如下:

    
    0:000> !dumpheap -mt 00007ffeb28320a0 -min 0n10485760
             Address               MT     Size
    0000000029051018 00007ffeb28320a0 33554456     
    000000002d051078 00007ffeb28320a0 33554456     
    00000003e6a43a10 00007ffeb28320a0 16777240     
    0000000547ff1000 00007ffeb28320a0 1195710200     
    000000058fff1000 00007ffeb28320a0 1195710200     
    000000064e821000 00007ffeb28320a0 1195759552     
    000000013bff1000 00007ffeb28320a0 1195759552     
    0000000257ff1000 00007ffeb28320a0 1195759560     
    total 8 objects
    Statistics:
                  MT    Count    TotalSize Class Name
    00007ffeb28320a0        8   6062585216 System.Byte[]
    Total 8 objects
    
    

    從卦中看,居然有 5 個將近 1.2 G 的 Byte[] 數組,有點嚇人,抽幾個看看吧。

    
    0:000> !gcroot 000000058fff1000
    Note: Roots found on stacks may be false positives. Run "!help gcroot" for
    more info.
    Scan Thread 0 OSTHread 39f4
    
    0:000> !gcroot 0000000547ff1000
    Note: Roots found on stacks may be false positives. Run "!help gcroot" for
    more info.
    Scan Thread 0 OSTHread 39f4
    Scan Thread 2 OSTHread 2f6c
    Scan Thread 3 OSTHread 3354
    Scan Thread 4 OSTHread 3924
    
    

    從卦中看,他們都沒有引用根,也就說明是等待 GC 回收的臨時對象,有朋友就要問了,GC 為什么不回收呢?

    2. GC 為什么不回收

    了解 GC 的朋友應該知道,LOH 默認不啟用壓縮回收,只會做簡單的標記清除,清除之后就會存在很多的空洞,只有相鄰的空洞才會合并成一個更大的空洞,一旦有分配的對象超過所有的空洞大小,GC 也只能被迫commit更多的新空間給它存放,雖然此時存放不間隔的空閑內存已經足夠。

    如果大家有點懵,畫個圖大概就像下面這樣。

    從圖中看,程序要分配 1.3G 的對象, 雖然 LOH 上有 2G 的空閑空間但就是放不下,無奈只能 commit 更多的內存來存放這個對象。

    這就是為什么朋友看到的,有時候內存會暴漲,有時候會降下去的底層原理。

    3. byte[] 到底是什么

    要想查看 byte[] 的內容,可以用 db, dW 觀察內存地址,參考如下:

    
    0:000> dW 0000000547ff1000 L100
    00000005`47ff1000  20a0 b283 7ffe 0000 16da 4745 0000 0000  . ........EG....
    00000005`47ff1010  0100 0000 ff00 ffff 01ff 0000 0000 0000  ................
    00000005`47ff1020  0c00 0002 0000 534e 7379 6574 2e6d 6144  ......NSystem.Da
    00000005`47ff1030  6174 202c 6556 7372 6f69 3d6e 2e32 2e30  ta, Version=2.0.
    00000005`47ff1040  2e30 2c30 4320 6c75 7574 6572 6e3d 7565  0.0, Culture=neu
    00000005`47ff1050  7274 6c61 202c 7550 6c62 6369 654b 5479  tral, PublicKeyT
    00000005`47ff1060  6b6f 6e65 623d 3737 3561 3563 3136 3339  oken=b77a5c56193
    00000005`47ff1070  6534 3830 0539 0001 0000 5315 7379 6574  4e089......Syste
    00000005`47ff1080  2e6d 6144 6174 442e 7461 5461 6261 656c  m.Data.DataTable
    00000005`47ff1090  04d6 0000 4419 7461 5461 6261 656c 522e  .....DataTable.R
    00000005`47ff10a0  6d65 746f 6e69 5667 7265 6973 6e6f 4418  emotingVersion.D
    00000005`47ff10b0  7461 5461 6261 656c 522e 6d65 746f 6e69  ataTable.Remotin
    00000005`47ff10c0  4667 726f 616d 1374 6144 6174 6154 6c62  gFormat.DataTabl
    00000005`47ff10d0  2e65 6154 6c62 4e65 6d61 1365 6144 6174  e.TableName.Data
    00000005`47ff10e0  6154 6c62 2e65 614e 656d 7073 6361 1065  Table.Namespace.
    00000005`47ff10f0  6144 6174 6154 6c62 2e65 7250 6665 7869  DataTable.Prefix
    00000005`47ff1100  4417 7461 5461 6261 656c 432e 7361 5365  .DataTable.CaseS
    00000005`47ff1110  6e65 6973 6974 6576 441e 7461 5461 6261  ensitive.DataTab
    00000005`47ff1120  656c 632e 7361 5365 6e65 6973 6974 6576  le.caseSensitive
    00000005`47ff1130  6d41 6962 6e65 1474 6144 6174 6154 6c62  Ambient.DataTabl
    00000005`47ff1140  2e65 6f4c 6163 656c 434c 4449 4419 7461  e.LocaleLCID.Dat
    00000005`47ff1150  5461 6261 656c 4d2e 6e69 6d69 6d75 6143  aTable.MinimumCa
    00000005`47ff1160  6170 6963 7974 4419 7461 5461 6261 656c  pacity.DataTable
    00000005`47ff1170  4e2e 7365 6574 4964 446e 7461 5361 7465  .NestedInDataSet
    00000005`47ff1180  4412 7461 5461 6261 656c 542e 7079 4e65  .DataTable.TypeN
    00000005`47ff1190  6d61 1b65 6144 6174 6154 6c62 2e65 6552  ame.DataTable.Re
    00000005`47ff11a0  6570 7461 6261 656c 6c45 6d65 6e65 1c74  peatableElement.
    00000005`47ff11b0  6144 6174 6154 6c62 2e65 7845 6574 646e  DataTable.Extend
    00000005`47ff11c0  6465 7250 706f 7265 6974 7365 4417 7461  edProperties.Dat
    00000005`47ff11d0  5461 6261 656c 432e 6c6f 6d75 736e 432e  aTable.Columns.C
    00000005`47ff11e0  756f 746e 4421 7461 5461 6261 656c 442e  ount!DataTable.D
    00000005`47ff11f0  7461 4361 6c6f 6d75 5f6e 2e30 6f43 756c  ataColumn_0.Colu
    ....
    
    

    從 unicode 碼來看,貌似是一個 DataTable 的序列化,看樣子是序列化一個巨大的 DataTable 導致的內存暴漲,接下來我們到線程棧上找到有么有類似的操作,算是碰碰運氣吧。

    哈哈,從卦中看還真的有類似操作,用了 BinaryFormatter 做序列化。。。接下來觀察下這個 DataTable 的 RowCount。

    
    0:013> !do 0000000002582cb8
    Name: System.Data.DataRowCollection+DataRowTree
    MethodTable: 00007ffea909d3f0
    EEClass: 00007ffea8f1ef68
    Size: 64(0x40) bytes
     (C:\Windows\assembly\GAC_64\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
    Fields:
                  MT    Field   Offset                 Type VT     Attr            Value Name
    0000000000000000  4000765        8              SZARRAY  0 instance 000000000bc79d98 _pageTable
    00007ffeb2831180  4000766       10       System.Int32[]  0 instance 000000000bc79fb8 _pageTableMap
    00007ffeb28312d0  4000767       18         System.Int32  1 instance               42 _inUsePageCount
    00007ffeb28312d0  4000768       1c         System.Int32  1 instance                1 nextFreePageLine
    00007ffeb28312d0  4000769       20         System.Int32  1 instance          1245312 root
    00007ffeb28312d0  400076a       24         System.Int32  1 instance            17054 _version
    00007ffeb28312d0  400076b       28         System.Int32  1 instance            17055 _inUseNodeCount
    00007ffeb28312d0  400076c       2c         System.Int32  1 instance                0 _inUseSatelliteTreeCount
    00007ffea957b578  400076d       30         System.Int32  1 instance                2 _accessMethod
    
    

    從卦中看當前的 _inUseNodeCount=1.7W ,這只是捕獲到的,相信還有更大的,也算是找到問題原因了。

    三:總結

    在和朋友溝通之后,朋友也確認了確實有大 DataTable 的情況,目前業務需求沒法繞過,不過在這種情況下也還是有辦法的,大致如下:

    1. 強制 LOH 壓縮

    雖然 LOH 上的對象移動會產生很大的內存流量,但適當的用一用壓縮也不失為一個簡單粗暴的辦法。

    
    GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
    GC.Collect();
    
    

    2. 分批次獲取

    一次性獲取 1.7W 條,可以拆成諸如 2000 條一次,好處很明顯,可以充分利用 LOH 上留下來的空洞區。

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有