Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

C#에서 만든 COM 객체를 C/C++로 P/Invoke Interop 시 메모리 누수(Memory Leak) 발생

닷넷 객체를 COM 방식으로 접근할 수 있도록 다음과 같이 만들 수 있습니다.

[ComVisible(true)]
[Guid("34CF251B-EAED-428D-9686-C5A5711D3A3E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMyUnk
{
    void Test();
}

[ComVisible(true)]
[Guid("c9f685ea-3388-3ff5-958a-3234d08587c1")]
[ClassInterface(ClassInterfaceType.None)]
public class MyUnkObject : IMyUnk
{
    public void Test()
    {
        // Console.WriteLine("Call: Test()");
    }
}

그럼 C++에서 이런 식으로 함수를 정의하면,

extern "C"
{
    interface IMyUnk : IUnknown
    {
    public:
        virtual HRESULT STDMETHODCALLTYPE Test() = 0;
    };

    __declspec(dllexport) void __cdecl UseIUnk(IUnknown *pUnk, bool doRelease)
    {
        if (pUnk == nullptr)
        {
            return;
        }

        IID iid;
        IIDFromString(L"{34CF251B-EAED-428D-9686-C5A5711D3A3E}", &iid);
        
        IMyUnk* myPtr = nullptr;
        if (pUnk->QueryInterface(iid, (LPVOID*)&myPtr) != S_OK)
        {
            return;
        }

        myPtr->Test();
        myPtr->Release();

        if (doRelease == true)
        {
            pUnk->Release();
        }
    }
}

C#에서 C++로 MyObject 객체를 다음과 같이 전달해 사용할 수 있습니다.

using DetourFunc.ClrType;
using System;
using System.Runtime.InteropServices;

namespace ConsoleApp1
{
    class Program
    {
        [DllImport("IUnkSample.dll")]
        internal static unsafe extern void UseIUnk([MarshalAs(UnmanagedType.Interface)] object unk, bool doRelease);

        static void Main(string[] args)
        {
            MyObject obj = new MyObject();
            UseIUnk(obj, true);
        }
    }
}




문제는 저렇게 interop을 하는 경우 메모리 누수가 발생한다는 겁니다. 실제로 아래와 같이 실행해 보면,

static void Main(string[] args)
{
    int i = 0;
    while (true)
    {
        TestHandleLeak();

        i++;

        if (i > 1000)
        {
            GC.Collect();
            GC.Collect();
            i = 0;
        }
    }
}

private unsafe static void TestHandleLeak()
{
    MyUnkObject obj = new MyUnkObject();
    UseIUnk(obj, true);
}

메모리가 증가하는 것을 확인할 수 있습니다. 얼핏 보면 이번에도 이전에 설명했던 것들과 비슷한 상황인 듯한데,

C# - Marshal.GetNativeVariantForObject 사용 시 메모리 누수(Memory Leak) 발생 및 해결 방법
; https://www.sysnet.pe.kr/2/0/12157

C# - Marshal.GetIUnknownForObject/GetIDispatchForObject 사용 시 메모리 누수(Memory Leak) 발생
; https://www.sysnet.pe.kr/2/0/12158

근본적인 원인은 다른 것 같습니다. 왜냐하면, !gchandles의 "Ref Count Handles"가 증가하지 않고 순수하게 닷넷 객체가 해제되지 않아 쌓이기 때문입니다. 게다가 C++ 측에서 VARIANT로 받아 VariantClear를 호출하는 식의 방법도,

// C++
__declspec(dllexport) void __cdecl UseObjectToVariant(VARIANT variant)
{
    VariantClear(&variant);
}


// C#
[DllImport("IUnkSample.dll")]
internal static unsafe extern void UseObjectToVariant(object variant);

private unsafe static void TestHandleLeak2()
{
    // object obj = new object();
    MyUnkObject obj = new MyUnkObject();
    UseObjectToVariant(obj);
            
    // UseObjectToVariant(5.5); // VARIANT의 데이터 필드에 저장할 수 있는 데이터는 메모리 누수가 없음
}

이번에는 해결책이 되지 못했습니다.




문제 유형은 다르지만, 그래도 해결 방식은 "C# - Marshal.GetIUnknownForObject/GetIDispatchForObject 사용 시 메모리 누수(Memory Leak) 발생" 글과 마찬가지로 다룰 수 있습니다.

해당 글에서 만든 (ObjectInterface 타입을 이름 변경한) VariantMarshaller 타입을 정리해 DetourFunc 라이브러리에 넣어 두었으니 NuGet을 통해,

Install-Package DetourFunc -Version 1.1.1

// 소스 코드: github - https://github.com/stjeong/DotNetSamples/tree/master/WinConsole/PEFormat/DetourFunc

참조 추가하면 다음과 같이 사용할 수 있습니다.

[DllImport("IUnkSample.dll")]
internal static unsafe extern void UseIntPtrToVariant(IntPtr variant);

private unsafe static void TestHandleWithoutLeak()
{
    MyUnkObject obj = new MyUnkObject();

    using (VariantMarshaller oi = new VariantMarshaller(obj))
    {
        UseIntPtrToVariant(oi.Variant);
    }
}

그리고 대응하는 C++ 함수에서는 그냥 사용만 하면 됩니다. (이후 실행해 확인하면 메모리 누수가 발생하지 않습니다.)

__declspec(dllexport) void __cdecl UseIntPtrToVariant(VARIANT *variant)
{
    // variant->punkVal // (IUnknown *)
}




그런데, 이런 식의 메모리 누수가 현실적으로 문제로 인식되는 경우는 많지 않습니다. 왜냐하면, .NET 객체를 COM 인터페이스로 Native에 넘기는 경우도 많지 않을 뿐더러, 그렇다고 해도 웬만큼 반복하지 않는 한 메모리 누수가 크게 부각되기까지는 꽤나 시간이 걸릴 것이기 때문입니다.

게다가 그 문제를 완화시키는 또 다른 사유로는, 이런 문제가 (Managed COM 객체가 아닌) Native COM 객체를 pinvoke로 전달할 때는 발생하지 않는다는 점입니다. 예를 들어, 아래의 코드는 메모리 누수가 발생하지 않습니다.

private unsafe static void TestHandleWithXmlDoc()
{
    Type type = Type.GetTypeFromProgID("Microsoft.XMLDOM");

    object xmlDoc = Activator.CreateInstance(type); // native COM 객체 생성
    UseIUnk(xmlDoc, false);
}

(첨부 파일은 이 글의 예제 코드를 포함합니다.)




참고로, pinvoke에서 object 인자의 마샬링 과정을 살펴보면 최초 UseIUnk 호출 시,

C:\ConsoleApp1\ConsoleApp1\Program.cs @ 47:
00007ffc`7cf40985 488b4df0        mov     rcx,qword ptr [rbp-10h]
00007ffc`7cf40989 e802fbffff      call    00007ffc`7cf40490 (ConsoleApp1.Program.UseIUnk(System.Object), mdToken: 0000000006000001)
00007ffc`7cf4098e 90              nop

마샬링을 위한 코드가 JIT 컴파일되는 과정을 동일하게 거쳐,

00007ffc`7cf40490 49ba005ae37cfc7f0000 mov r10,7FFC7CE35A00h
00007ffc`7cf4049a 40e96043545f    jmp     clr!ThePreStub (00007ffc`dc484800)

clr!ThePreStub:
00007ffc`dc484800 4157            push    r15
00007ffc`dc484802 4156            push    r14
00007ffc`dc484804 4155            push    r13
00007ffc`dc484806 4154            push    r12
00007ffc`dc484808 55              push    rbp
00007ffc`dc484809 53              push    rbx
00007ffc`dc48480a 56              push    rsi
00007ffc`dc48480b 57              push    rdi
00007ffc`dc48480c 4883ec68        sub     rsp,68h
00007ffc`dc484810 48898c24b0000000 mov     qword ptr [rsp+0B0h],rcx
00007ffc`dc484818 48899424b8000000 mov     qword ptr [rsp+0B8h],rdx
00007ffc`dc484820 4c898424c0000000 mov     qword ptr [rsp+0C0h],r8
00007ffc`dc484828 4c898c24c8000000 mov     qword ptr [rsp+0C8h],r9
00007ffc`dc484830 660f7f442420    movdqa  xmmword ptr [rsp+20h],xmm0
00007ffc`dc484836 660f7f4c2430    movdqa  xmmword ptr [rsp+30h],xmm1
00007ffc`dc48483c 660f7f542440    movdqa  xmmword ptr [rsp+40h],xmm2
00007ffc`dc484842 660f7f5c2450    movdqa  xmmword ptr [rsp+50h],xmm3
00007ffc`dc484848 488d4c2468      lea     rcx,[rsp+68h]
00007ffc`dc48484d 498bd2          mov     rdx,r10
00007ffc`dc484850 e8eba30000      call    clr!PreStubWorker (00007ffc`dc48ec40)
00007ffc`dc484855 660f6f442420    movdqa  xmm0,xmmword ptr [rsp+20h]
00007ffc`dc48485b 660f6f4c2430    movdqa  xmm1,xmmword ptr [rsp+30h]
00007ffc`dc484861 660f6f542440    movdqa  xmm2,xmmword ptr [rsp+40h]
00007ffc`dc484867 660f6f5c2450    movdqa  xmm3,xmmword ptr [rsp+50h]
00007ffc`dc48486d 488b8c24b0000000 mov     rcx,qword ptr [rsp+0B0h]
00007ffc`dc484875 488b9424b8000000 mov     rdx,qword ptr [rsp+0B8h]
00007ffc`dc48487d 4c8b8424c0000000 mov     r8,qword ptr [rsp+0C0h]
00007ffc`dc484885 4c8b8c24c8000000 mov     r9,qword ptr [rsp+0C8h]
00007ffc`dc48488d 4883c468        add     rsp,68h
00007ffc`dc484891 5f              pop     rdi
00007ffc`dc484892 5e              pop     rsi
00007ffc`dc484893 5b              pop     rbx
00007ffc`dc484894 5d              pop     rbp
00007ffc`dc484895 415c            pop     r12
00007ffc`dc484897 415d            pop     r13
00007ffc`dc484899 415e            pop     r14
00007ffc`dc48489b 415f            pop     r15
00007ffc`dc48489d 48ffe0          jmp     rax  // JIT 컴파일 시켜 jmp 코드로 바뀐 원래의 호출 위치로 다시 JMP (rax == 00007ffc`7cf40490)

00007ffc`7cf40490 49ba005ae37cfc7f0000 mov r10,7FFC7CE35A00h
00007ffc`7cf4049a 40e910050000    jmp     00007ffc`7cf409b0  // Jit된 대상 메서드로 JMP

PInvoke 층의 메서드 내에서 InterfaceMarshaler__ConvertToNative 함수를 통해 "object" 인자를 native로 전달하기 위한 마샬링 작업을 수행합니다.

00007ffc`7cf409b0 55              push    rbp
00007ffc`7cf409b1 4157            push    r15
00007ffc`7cf409b3 4156            push    r14
00007ffc`7cf409b5 4155            push    r13
00007ffc`7cf409b7 4154            push    r12
00007ffc`7cf409b9 57              push    rdi
00007ffc`7cf409ba 56              push    rsi
00007ffc`7cf409bb 53              push    rbx
00007ffc`7cf409bc 4881ec98000000  sub     rsp,98h
00007ffc`7cf409c3 488dac24d0000000 lea     rbp,[rsp+0D0h]
00007ffc`7cf409cb 4c8955a0        mov     qword ptr [rbp-60h],r10
00007ffc`7cf409cf 4889a550ffffff  mov     qword ptr [rbp-0B0h],rsp
00007ffc`7cf409d6 48894d10        mov     qword ptr [rbp+10h],rcx
00007ffc`7cf409da 488d8d68ffffff  lea     rcx,[rbp-98h]
00007ffc`7cf409e1 498bd2          mov     rdx,r10
00007ffc`7cf409e4 e85744545f      call    clr!JIT_InitPInvokeFrame (00007ffc`dc484e40)
00007ffc`7cf409e9 488945a8        mov     qword ptr [rbp-58h],rax
00007ffc`7cf409ed 488bcc          mov     rcx,rsp
00007ffc`7cf409f0 48894d88        mov     qword ptr [rbp-78h],rcx
00007ffc`7cf409f4 488bcd          mov     rcx,rbp
00007ffc`7cf409f7 48894d98        mov     qword ptr [rbp-68h],rcx
00007ffc`7cf409fb 488b4da8        mov     rcx,qword ptr [rbp-58h]
00007ffc`7cf409ff 488d8568ffffff  lea     rax,[rbp-98h]
00007ffc`7cf40a06 48894110        mov     qword ptr [rcx+10h],rax
00007ffc`7cf40a0a 488b4da0        mov     rcx,qword ptr [rbp-60h]
00007ffc`7cf40a0e e87d06685f      call    clr!StubHelpers::DemandPermission (00007ffc`dc5c1090)
00007ffc`7cf40a13 4533c0          xor     r8d,r8d
00007ffc`7cf40a16 448945c4        mov     dword ptr [rbp-3Ch],r8d
00007ffc`7cf40a1a 90              nop
00007ffc`7cf40a1b 4533c0          xor     r8d,r8d
00007ffc`7cf40a1e 4d63c0          movsxd  r8,r8d
00007ffc`7cf40a21 33d2            xor     edx,edx
00007ffc`7cf40a23 4863d2          movsxd  rdx,edx
00007ffc`7cf40a26 488b4d10        mov     rcx,qword ptr [rbp+10h]
00007ffc`7cf40a2a 41b910000000    mov     r9d,10h
00007ffc`7cf40a30 e85b8c625f      call    clr!StubHelpers::InterfaceMarshaler__ConvertToNative (00007ffc`dc569690)
00007ffc`7cf40a35 488945b8        mov     qword ptr [rbp-48h],rax
00007ffc`7cf40a39 c745c401000000  mov     dword ptr [rbp-3Ch],1
00007ffc`7cf40a40 90              nop
00007ffc`7cf40a41 488b4da0        mov     rcx,qword ptr [rbp-60h]
00007ffc`7cf40a45 41bb20000000    mov     r11d,20h
...[생략]...

InterfaceMarshaler__ConvertToNative 호출 시점의 rcx에는 object 인자의 GC Heap 주소가 담겨 있습니다. InterfaceMarshaler__ConvertToNative 함수가 기존의 Marshal.GetIUnknownForObject, Marshal.GetNativeVariantForObject와 다른 점은 내부에서 "clr!MarshalObjectToInterface" 함수를 부른다는 정도입니다.

clr!StubHelpers::InterfaceMarshaler__ConvertToNative:
00007ffc`dc569690 44894c2420      mov     dword ptr [rsp+20h],r9d ss:00000000`003ee7b8=02502df0
00007ffc`dc569695 4c89442418      mov     qword ptr [rsp+18h],r8
00007ffc`dc56969a 4889542410      mov     qword ptr [rsp+10h],rdx
00007ffc`dc56969f 53              push    rbx
00007ffc`dc5696a0 56              push    rsi
00007ffc`dc5696a1 57              push    rdi
00007ffc`dc5696a2 4154            push    r12
00007ffc`dc5696a4 4155            push    r13
00007ffc`dc5696a6 4156            push    r14
00007ffc`dc5696a8 4157            push    r15
00007ffc`dc5696aa 4881ec60010000  sub     rsp,160h
00007ffc`dc5696b1 48c7442458feffffff mov   qword ptr [rsp+58h],0FFFFFFFFFFFFFFFEh
00007ffc`dc5696ba 458bf1          mov     r14d,r9d
00007ffc`dc5696bd 4d8bf8          mov     r15,r8
00007ffc`dc5696c0 4c8be2          mov     r12,rdx
00007ffc`dc5696c3 488d35c6ffffff  lea     rsi,[clr!StubHelpers::InterfaceMarshaler__ConvertToNative (00007ffc`dc569690)]
00007ffc`dc5696ca 4889742438      mov     qword ptr [rsp+38h],rsi
00007ffc`dc5696cf 4885c9          test    rcx,rcx
00007ffc`dc5696d2 0f84d0000000    je      clr!StubHelpers::InterfaceMarshaler__ConvertToNative+0x118 (00007ffc`dc5697a8)
00007ffc`dc5696d8 488364243000    and     qword ptr [rsp+30h],0

00007ffc`dc5696de 48894c2428      mov     qword ptr [rsp+28h],rcx
00007ffc`dc5696e3 c784249000000040000000 mov dword ptr [rsp+90h],40h
00007ffc`dc5696ee 4889b424a0000000 mov     qword ptr [rsp+0A0h],rsi
00007ffc`dc5696f6 488d05fb886e00  lea     rax,[clr!HelperMethodFrame_1OBJ::`vftable' (00007ffc`dcc51ff8)]
00007ffc`dc5696fd 4889442478      mov     qword ptr [rsp+78h],rax
00007ffc`dc569702 488d442428      lea     rax,[rsp+28h]
00007ffc`dc569707 4889842450010000 mov     qword ptr [rsp+150h],rax
00007ffc`dc56970f 488d8c24a8000000 lea     rcx,[rsp+0A8h]
00007ffc`dc569717 e8d4b7f1ff      call    clr!LazyMachStateCaptureState (00007ffc`dc484ef0)
00007ffc`dc56971c 488d4c2478      lea     rcx,[rsp+78h]
00007ffc`dc569721 e80ab8f1ff      call    clr!HelperMethodFrame::Push (00007ffc`dc484f30)
00007ffc`dc569726 488b8c2498000000 mov     rcx,qword ptr [rsp+98h]
00007ffc`dc56972e 33ff            xor     edi,edi
00007ffc`dc569730 4532ed          xor     r13b,r13b
00007ffc`dc569733 8a05ff989200    mov     al,byte ptr [clr!g_StackProbingEnabled (00007ffc`dce93038)]
00007ffc`dc569739 84c0            test    al,al
00007ffc`dc56973b 0f851b3e3000    jne     clr!StubHelpers::InterfaceMarshaler__ConvertToNative+0x303ecc (00007ffc`dc86d55c)

00007ffc`dc569741 458bce          mov     r9d,r14d
00007ffc`dc569744 4d8bc7          mov     r8,r15
00007ffc`dc569747 498bd4          mov     rdx,r12
00007ffc`dc56974a 488d4c2428      lea     rcx,[rsp+28h]
00007ffc`dc56974f e864000000      call    clr!MarshalObjectToInterface (00007ffc`dc5697b8)
00007ffc`dc569754 488bd8          mov     rbx,rax
00007ffc`dc569757 4889442430      mov     qword ptr [rsp+30h],rax
00007ffc`dc56975c c644244800      mov     byte ptr [rsp+48h],0
00007ffc`dc569761 803dd098920000  cmp     byte ptr [clr!g_StackProbingEnabled (00007ffc`dce93038)],0
00007ffc`dc569768 0f85123e3000    jne     clr!StubHelpers::InterfaceMarshaler__ConvertToNative+0x303ef0 (00007ffc`dc86d580)
00007ffc`dc56976e 4584ed          test    r13b,r13b
00007ffc`dc569771 7539            jne     clr!StubHelpers::InterfaceMarshaler__ConvertToNative+0x11c (00007ffc`dc5697ac)
00007ffc`dc569773 488d4c2478      lea     rcx,[rsp+78h]
00007ffc`dc569778 e8f3b7f1ff      call    clr!HelperMethodFrame::Pop (00007ffc`dc484f70)
00007ffc`dc56977d 488d8c24a8000000 lea     rcx,[rsp+0A8h]
00007ffc`dc569785 e846acf1ff      call    clr!HelperMethodFrameRestoreState (00007ffc`dc4843d0)
00007ffc`dc56978a 85c0            test    eax,eax
00007ffc`dc56978c 0f8551ffffff    jne     clr!StubHelpers::InterfaceMarshaler__ConvertToNative+0x53 (00007ffc`dc5696e3)
00007ffc`dc569792 488bc3          mov     rax,rbx
00007ffc`dc569795 4881c460010000  add     rsp,160h
00007ffc`dc56979c 415f            pop     r15
00007ffc`dc56979e 415e            pop     r14
00007ffc`dc5697a0 415d            pop     r13
00007ffc`dc5697a2 415c            pop     r12
00007ffc`dc5697a4 5f              pop     rdi
00007ffc`dc5697a5 5e              pop     rsi
00007ffc`dc5697a6 5b              pop     rbx
00007ffc`dc5697a7 c3              ret

실제로 rcx에 object의 [주소를 가리키는 주솟값]을 담아 MarshalObjectToInterface 호출하고 반환받은 rax값을 살펴보면,

00007ffc`dc56974f e864000000      call    clr!MarshalObjectToInterface (00007ffc`dc5697b8)
                        // 결괏값: rax == 00000000`007c0018

0:000> dq @rax L1
00000000`007c0018 0000000000960938 // IDispatch

IDispatch 인터페이스를 가리키는 포인터가 담겨 있음을 알 수 있습니다.

0:000> dq 0000000000960938 L7
00000000`00960938 00007ffcdc5692f0 00007ffcdc4d7920 00007ffcdc568e50 00007ffcdc9dc1a0
00000000`00960958 00007ffcdc9dc370 00007ffcdc9dbf70 00007ffcdc9dc5b0 

00007ffcdc5692f0부터 00007ffcdc9dc5b0까지의 7개 주소는 IDispatch의 정의 따라 각각 다음의 함수 진입점을 가리키고 있습니다.

clr!Unknown_QueryInterface:
clr!Unknown_AddRef:
clr!Unknown_Release:
clr!Dispatch_GetTypeInfoCount_Wrapper:
clr!Dispatch_GetTypeInfo_Wrapper:
clr!Dispatch_GetIDsOfNames_Wrapper:
clr!Dispatch_Invoke_Wrapper:

이는 IUnknown/IDispatch에서 정의한 함수의 순서와 정확히 일치합니다.

MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
IUnknown
{
public:
    BEGIN_INTERFACE
    virtual HRESULT STDMETHODCALLTYPE QueryInterface( 
        /* [in] */ REFIID riid,
        /* [annotation][iid_is][out] */ 
        _COM_Outptr_  void **ppvObject) = 0;
        
    virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
        
    virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
        
    END_INTERFACE
};

MIDL_INTERFACE("00020400-0000-0000-C000-000000000046")
IDispatch : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
        /* [out] */ __RPC__out UINT *pctinfo) = 0;
        
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfo( 
        /* [in] */ UINT iTInfo,
        /* [in] */ LCID lcid,
        /* [out] */ __RPC__deref_out_opt ITypeInfo **ppTInfo) = 0;
        
    virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( 
        /* [in] */ __RPC__in REFIID riid,
        /* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames,
        /* [range][in] */ __RPC__in_range(0,16384) UINT cNames,
        /* [in] */ LCID lcid,
        /* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID *rgDispId) = 0;
        
    virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( 
        /* [annotation][in] */ 
        _In_  DISPID dispIdMember,
        /* [annotation][in] */ 
        _In_  REFIID riid,
        /* [annotation][in] */ 
        _In_  LCID lcid,
        /* [annotation][in] */ 
        _In_  WORD wFlags,
        /* [annotation][out][in] */ 
        _In_  DISPPARAMS *pDispParams,
        /* [annotation][out] */ 
        _Out_opt_  VARIANT *pVarResult,
        /* [annotation][out] */ 
        _Out_opt_  EXCEPINFO *pExcepInfo,
        /* [annotation][out] */ 
        _Out_opt_  UINT *puArgErr) = 0;
};




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]





[최초 등록일: ]
[최종 수정일: 2/28/2020 ]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer@outlook.com

비밀번호

댓글 쓴 사람
 




1  2  3  4  5  6  7  8  9  10  11  12  13  14  [15]  ...
NoWriterDateCnt.TitleFile(s)
12070정성태12/9/20192278오류 유형: 581. resize2fs: Bad magic number in super-block while trying to open /dev/.../root
12069정성태12/19/20191246디버깅 기술: 139. windbg - x64 덤프 분석 시 메서드의 인자 또는 로컬 변수의 값을 확인하는 방법
12068정성태11/28/20192118디버깅 기술: 138. windbg와 Win32 API로 알아보는 Windows Heap 정보 분석 [2]파일 다운로드2
12067정성태11/27/20191177디버깅 기술: 137. 실제 사례를 통해 Debug Diagnostics 도구가 생성한 닷넷 웹 응용 프로그램의 성능 장애 보고서 설명 [1]파일 다운로드1
12066정성태11/27/2019967디버깅 기술: 136. windbg - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석 - OracleCommand.ExecuteReader에서 OpsSql.Prepare2 PInvoke 호출 분석
12065정성태11/25/20191050디버깅 기술: 135. windbg - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석파일 다운로드1
12064정성태11/25/20191635오류 유형: 580. HTTP Error 500.0/500.33 - ANCM In-Process Handler Load Failure
12063정성태11/21/20191317디버깅 기술: 134. windbg - RtlReportCriticalFailure로부터 parameters 정보 찾는 방법
12062정성태12/20/20191044디버깅 기술: 133. windbg - CoTaskMemFree/FreeCoTaskMem에서 발생한 덤프 분석 사례 - 두 번째 이야기
12061정성태9/24/20201165Windows: 167. CoTaskMemAlloc/CoTaskMemFree과 윈도우 Heap의 관계
12060정성태11/21/20191237디버깅 기술: 132. windbg/Visual Studio - HeapFree x64의 동작 분석
12059정성태11/20/20191240디버깅 기술: 131. windbg/Visual Studio - HeapFree x86의 동작 분석
12058정성태11/19/20191181디버깅 기술: 130. windbg - CoTaskMemFree/FreeCoTaskMem에서 발생한 덤프 분석 사례
12057정성태11/18/2019784오류 유형: 579. Visual Studio - Memory 창에서 유효한 주소 영역임에도 "Unable to evaluate the expression." 오류 출력
12056정성태11/18/20191534개발 환경 구성: 464. "Microsoft Visual Studio Installer Projects" 프로젝트로 EXE 서명 및 MSI 파일 서명 방법파일 다운로드1
12055정성태11/17/2019752개발 환경 구성: 463. Visual Studio의 Ctrl + Alt + M, 1 (Memory 1) 등의 단축키가 동작하지 않는 경우
12054정성태11/15/20191188.NET Framework: 869. C# - 일부러 GC Heap을 깨뜨려 GC 수행 시 비정상 종료시키는 예제
12053정성태9/24/2020908Windows: 166. 윈도우 10 - 명령행 창(cmd.exe) 속성에 (DotumChe, GulimChe, GungsuhChe 등의) 한글 폰트가 없는 경우
12052정성태11/15/2019865오류 유형: 578. Azure - 일정(schedule)에 등록한 runbook이 1년 후 실행이 안 되는 문제(Reason - The key used is expired.)
12051정성태12/2/20191990개발 환경 구성: 462. 시작하자마자 비정상 종료하는 프로세스의 메모리 덤프 - procdump [1]
12050정성태9/24/20201235Windows: 165. AcLayers의 API 후킹과 FaultTolerantHeap
12049정성태11/13/2019896.NET Framework: 868. (닷넷 프로세스를 대상으로) 디버거 방식이 아닌 CLR Profiler를 이용해 procdump.exe 기능 구현
12048정성태9/24/20201332Windows: 164. GUID 이름의 볼륨에 해당하는 파티션을 찾는 방법
12047정성태11/12/20192041Windows: 163. 안전하게 eject시킨 USB 장치를 물리적인 재연결 없이 다시 인식시키는 방법
12046정성태11/9/20191054오류 유형: 577. windbg - The call to LoadLibrary(...\sos.dll) failed, Win32 error 0n193
12045정성태10/27/2019828오류 유형: 576. mstest.exe 실행 시 "Visual Studio Enterprise is required to execute the test." 오류 - 두 번째 이야기
1  2  3  4  5  6  7  8  9  10  11  12  13  14  [15]  ...