1 using System.Runtime.InteropServices; 2 3 namespace ExampleCore_7_01 4 { 5 internal class Program 6 { 7 [DllImport("Kernel32.dll", SetLastError = true)] 8 private static extern bool Beep(uint freq, uint dur); 9 10 static void Main(string[] args) 11 { 12 Beep(1000, 1000); 13 14 Console.ReadLine(); 15 } 16 } 17 }
1 using System.Runtime.InteropServices; 2 3 namespace ExampleCore_7_02 4 { 5 internal class Program 6 { 7 [DllImport("ExampleCore_7_022.dll", CallingConvention = CallingConvention.FastCall, CharSet = CharSet.Unicode)] 8 public static extern void Alloc(string str); 9 static void Main(string[] args) 10 { 11 var str = "hello world"; 12 13 Alloc(str); 14 15 Console.ReadLine(); 16 } 17 } 18 }
1 extern "C" 2 { 3 __declspec(dllexport) void Alloc(wchar_t* c); 4 } 5 6 #include "iostream" 7 #include <Windows.h> 8 9 using namespace std; 10 11 void Alloc(wchar_t* c) 12 { 13 wprintf(L"%s \n", c); 14 }
1 using System.Runtime.InteropServices; 2 3 namespace ExampleCore_7_03 4 { 5 internal class Program 6 { 7 //static GCHandle handle; 1、 8 9 public delegate void Callback(int i); 10 11 static void Main(string[] args) 12 { 13 TestCallback(); 14 GC.Collect(); //(在 Net Framework 环境下,不注释,就出问题,注释掉就没问题;在 .NET 8.0 环境,注释与否都不出错)。 15 Console.WriteLine("Press any key to exit"); 16 Console.ReadLine(); 17 } 18 19 private static void TestCallback() 20 { 21 Callback? callback = MyCallback; 22 //handle=GCHandle.Alloc(callback, GCHandleType.Normal); 2、 23 24 AsyncProcess(callback); 25 26 callback = null; 27 } 28 29 private static void MyCallback(int result) 30 { 31 Console.WriteLine($"回调的结果:Result={result}"); 32 } 33 34 [DllImport("ExampleCore_7_033", CallingConvention = CallingConvention.StdCall)] 35 private static extern void AsyncProcess(Callback callback); 36 } 37 }
1 #include <iostream> 2 #include <Windows.h> 3 using namespace std; 4 5 typedef void(__stdcall* PCallback)(UINT result); 6 7 extern "C" 8 { 9 _declspec(dllexport) void __stdcall AsyncProcess(PCallback ptr); 10 } 11 12 DWORD WINAPI ThreadWorkItem(LPVOID lpParameter) 13 { 14 printf("C++ 的工作线程,tid=%d \n", GetCurrentThreadId()); 15 16 Sleep(2000); 17 18 PCallback callback = (PCallback)lpParameter; 19 20 callback(5); 21 22 return 0; 23 } 24 25 void __stdcall AsyncProcess(PCallback ptr) 26 { 27 HANDLE hThread = CreateThread(NULL, 0, ThreadWorkItem, ptr, 0, NULL); 28 }
3.6、ExampleCore_7_04
1 using System.Runtime.InteropServices; 2 using System.Text; 3 4 namespace ExampleCore_7_04 5 { 6 internal class Program 7 { 8 static void Main(string[] args) 9 { 10 Console.WriteLine("请输入迭代的次数。"); 11 if (int.TryParse(Console.ReadLine(), out int it)) 12 { 13 StringBuilder stringBuilder = new StringBuilder(200); 14 for (int i = 0; i < it; i++) 15 { 16 GetDate(stringBuilder); 17 } 18 19 GC.Collect(); 20 } 21 22 Console.WriteLine("Press any key to exit!"); 23 Console.ReadLine(); 24 } 25 26 [DllImport("ExampleCore_7_044.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)] 27 private static extern void GetDate(StringBuilder date); 28 } 29 }
3.7、ExampleCore_7_044(动态链接库,C++)
1 #include <iostream> 2 #include <Windows.h> 3 using namespace std; 4 5 extern "C" 6 { 7 _declspec(dllexport) void __stdcall GetDate(WCHAR* pszDate); 8 } 9 10 void __stdcall GetDate(WCHAR* pszDate) 11 { 12 SYSTEMTIME time; 13 WCHAR* pszTmpDate = new WCHAR[200]; 14 15 GetSystemTime(&time); 16 17 wsprintf(pszTmpDate, L"%d-%d-%d", time.wMonth, time.wDay, time.wYear); 18 19 wcscpy(pszDate, pszTmpDate); 20 }
1 0:000> x kernel32!*beep* 2 00007ffd`e45b6980 KERNEL32!BeepImplementation (BeepImplementation) 3 00007ffd`e4602418 KERNEL32!_imp_Beep = <no type information>
有了地址,我们就可以针对这个地址下断点,执行命令【bp 00007ffd`e45b6980】,或者【bp KERNEL32!BeepImplementation】这两种形式都是可以的。我们可以使用【bl】命令查看断点列表。
1 0:000> bp 00007ffd`e45b6980 2 0:000> bl 3 0 e 00007ffd`e45b6980 0001 (0001) 0:**** KERNEL32!BeepImplementation 4 0:000>
断点设置成功后,【g】直接运行调试器,它会在断点出暂停。
1 0:000> g 2 ModLoad: 00007ffd`e6150000 00007ffd`e6182000 C:\Windows\System32\IMM32.DLL 3 ModLoad: 00007ffd`c77e0000 00007ffd`c7839000 C:\Program Files\dotnet\host\fxr\8.0.4\hostfxr.dll 4 ModLoad: 00007ffd`28960000 00007ffd`289c4000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\hostpolicy.dll 5 ModLoad: 00007ffd`0cca0000 00007ffd`0d186000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\coreclr.dll 6 ModLoad: 00007ffd`e4cf0000 00007ffd`e4e1b000 C:\Windows\System32\ole32.dll 7 ModLoad: 00007ffd`e4990000 00007ffd`e4ce3000 C:\Windows\System32\combase.dll 8 ModLoad: 00007ffd`e4820000 00007ffd`e48ed000 C:\Windows\System32\OLEAUT32.dll 9 ModLoad: 00007ffd`e3f80000 00007ffd`e4002000 C:\Windows\System32\bcryptPrimitives.dll 10 (48c4.479c): Unknown exception - code 04242420 (first chance) 11 ModLoad: 00007ffd`0c010000 00007ffd`0cc9c000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Private.CoreLib.dll 12 ModLoad: 00007ffd`0ee90000 00007ffd`0f049000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\clrjit.dll 13 ModLoad: 00007ffd`e3b90000 00007ffd`e3ba2000 C:\Windows\System32\kernel.appcore.dll 14 ModLoad: 00000289`b4cf0000 00000289`b4cf8000 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_7_01\bin\Debug\net8.0\ExampleCore_7_01.dll 15 ModLoad: 00000289`b4d00000 00000289`b4d0e000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Runtime.dll 16 ModLoad: 00007ffd`c37c0000 00007ffd`c37e8000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Console.dll 17 Breakpoint 0 hit 18 KERNEL32!BeepImplementation: 19 00007ffd`e45b6980 48895c2418 mov qword ptr [rsp+18h],rbx ss:000000b3`e0f9e6b0=000000b3e0f9e9a0
我们此时使用【!clrstack】命令看看栈回溯。
1 0:000> !clrstack 2 OS Thread Id: 0x479c (0) 3 Child SP IP Call Site 4 000000B3E0F9E6C8 00007ffde45b6980 [InlinedCallFrame: 000000b3e0f9e6c8] ExampleCore_7_01.Program.Beep(UInt32, UInt32) 5 000000B3E0F9E6C8 00007ffcad271a63 [InlinedCallFrame: 000000b3e0f9e6c8] ExampleCore_7_01.Program.Beep(UInt32, UInt32) 6 000000B3E0F9E6A0 00007FFCAD271A63 ILStubClass.IL_STUB_PInvoke(UInt32, UInt32) 7 000000B3E0F9E790 00007FFCAD271963 ExampleCore_7_01.Program.Main(System.String[])
我们看到了 ExampleCore_7_01.Program.Main 方法调用了 ExampleCore_7_01.Program.Beep 方法。ExampleCore_7_01.Program.Beep 方法对应的栈帧有如下一个前缀:[InlinedCallFrame: 000000b3e0f9e6c8]
000000b3e0f9e6c8 这个地址我们使用【dp 000000b3e0f9e6c8】命令查看一下它的内容。1 0:000> dp 000000b3e0f9e6c8 2 000000b3`e0f9e6c8 00007ffd`0d09a548 ffffffff`ffffffff 3 000000b3`e0f9e6d8 00007ffc`ad3200c0 00007ffc`ad3200c0 4 000000b3`e0f9e6e8 000000b3`e0f9e6a0 00007ffc`ad271a63 5 000000b3`e0f9e6f8 000000b3`e0f9e780 00000000`b7808e98 6 000000b3`e0f9e708 00007ffc`ad3200c0 00000289`b3427b10 7 000000b3`e0f9e718 00000000`00000000 00007ffd`e45b6980 8 000000b3`e0f9e728 00000000`00000000 00000000`000003e8 9 000000b3`e0f9e738 00000000`000003e8 00000000`00000001
00007ffd`0d09a548 针对这个地址,我们使用【ln 00007ffd`0d09a548】命令,是什么东西。
1 0:000> ln 00007ffd`0d09a548 2 (00007ffd`0d09a548) coreclr!InlinedCallFrame::`vftable' | (00007ffd`0d09a5d8) coreclr!vtable_DebuggerSecurityCodeMarkFrame 3 Exact matches: 4 coreclr!vtable_InlinedCallFrame = 0x00007ffd`0cdf9d80 5 coreclr!InlinedCallFrame::`vftable' = <function> *[18]
1 0:000> dp 00007ffd`0d09a548 2 00007ffd`0d09a548 00007ffd`0cdf9d80 00007ffd`0cdf9d90 3 00007ffd`0d09a558 00007ffd`0cdf9d80 00007ffd`0cdf8ac0 4 00007ffd`0d09a568 00007ffd`0cdf9de0 00007ffd`0cd5cbf0 5 00007ffd`0d09a578 00007ffd`0cea42b0 00007ffd`0cdf9d90 6 00007ffd`0d09a588 00007ffd`0cd5c4d0 00007ffd`0cdc1750 7 00007ffd`0d09a598 00007ffd`0cdf9d90 00007ffd`0cd5c4f0 8 00007ffd`0d09a5a8 00007ffd`0cdf9d90 00007ffd`0cdfa060 9 00007ffd`0d09a5b8 00007ffd`0cdf9d90 00007ffd`0cea4320
00007ffd`0cdf9d80 针对这个地址,我们继续使用【ln 00007ffd`0cdf9d80】命令看看它的内容。
1 0:000> ln 00007ffd`0cdf9d80 2 (00007ffd`0cdf9d80) coreclr!LoaderAllocator::CleanupDependentHandlesToNativeObjects | (00007ffd`0cdf9d90) coreclr!BaseDomain::IsAppDomain 3 Exact matches: 4 coreclr!DebuggerController::TriggerFuncEvalExit (class Thread *) 5 coreclr!standalone::GCToEEInterface::WalkAsyncPinnedForPromotion (class Object *, struct ScanContext *, <function> *) 6 coreclr!DispatchStubState::SetLastError (int) 7 coreclr!BINDER_SPACE::AssemblyVersion::~AssemblyVersion (void) 8 coreclr!ThreadDebugBlockingInfo::~ThreadDebugBlockingInfo (void) 9 coreclr!StubCacheBase::AddStub (unsigned char *, class Stub *) 10 coreclr!DispatchStubState::MarshalLCID (int) 11 coreclr!JIT_DebugLogLoopCloning (void) 12 coreclr!SVR::GCHeap::Shutdown (void) 13 coreclr!LoaderAllocator::UnregisterDependentHandleToNativeObjectFromCleanup (class LADependentHandleToNativeObject *) 14 coreclr!DispatchStubState::MarshalReturn (class MarshalInfo *, int) 15 coreclr!StgPoolSeg::~StgPoolSeg (void) 16 coreclr!noncopyable::~noncopyable (void) 17 coreclr!standalone::GCToEEInterface::WalkAsyncPinned (class Object *, void *, <function> *) 18 coreclr!HashMap::Iterator::~Iterator (void) 19 coreclr!standalone::GCToEEInterface::SyncBlockCachePromotionsGranted (int) 20 coreclr!EEClass::~EEClass (void) 21 coreclr!ILMarshaler::EmitCreateMngdMarshaler (class ILCodeStream *) 22 coreclr!ILMarshaler::EmitClearCLR (class ILCodeStream *) 23 coreclr!CEEInfo::methodMustBeLoadedBeforeCodeIsRun (struct CORINFO_METHOD_STRUCT_ *) 24 coreclr!LADependentNativeObject::~LADependentNativeObject (void) 25 coreclr!CEEJitInfo::recordCallSite (unsigned int, struct CORINFO_SIG_INFO *, struct CORINFO_METHOD_STRUCT_ *) 26 coreclr!Frame::ExceptionUnwind (void) 27 coreclr!EEDbgInterfaceImpl::ClearThreadException (class Thread *) 28 coreclr!MethodTable::MethodDataInterfaceImpl::UpdateImplMethodDesc (class MethodDesc *, unsigned int) 29 coreclr!DebuggerController::TriggerMethodEnter (class Thread *, class DebuggerJitInfo *, unsigned char *, class FramePointer) 30 coreclr!DebuggerController::TriggerUnwind (class Thread *, class MethodDesc *, class DebuggerJitInfo *, unsigned int64, class FramePointer, CorDebugStepReason) 31 coreclr!DebuggerController::DebuggerDetachClean (void) 32 coreclr!LoaderAllocator::RegisterDependentHandleToNativeObjectForCleanup (class LADependentHandleToNativeObject *) 33 coreclr!ComPrestubMethodFrame::ExceptionUnwind (void) 34 coreclr!EEDbgInterfaceImpl::DebuggerModifyingLogSwitch (int, wchar_t *) 35 coreclr!CEEInfo::updateEntryPointForTailCall (struct CORINFO_CONST_LOOKUP *) 36 coreclr!ILMarshaler::EmitConvertSpaceCLRToNative (class ILCodeStream *) 37 coreclr!EETypeHashTable::Iterator::~Iterator (void) 38 coreclr!InstMethodHashTable::Iterator::~Iterator (void) 39 coreclr!LoaderAllocator::ReleaseManagedAssemblyLoadContext (void) 40 coreclr!ILMarshaler::EmitConvertContentsCLRToNative (class ILCodeStream *) 41 coreclr!DebuggerController::TriggerFuncEvalEnter (class Thread *) 42 coreclr!CrossLoaderAllocatorHash<MethodDescBackpatchInfoTracker::BackpatchInfoTrackerHashTraits>::KeyValueStoreOrLAHashKeyToTrackers::~KeyValueStoreOrLAHashKeyToTrackers (void) 43 coreclr!PtrHashMap::PtrIterator::~PtrIterator (void) 44 coreclr!ILMarshaler::EmitSetupArgumentForMarshalling (class ILCodeStream *) 45 coreclr!ILMarshaler::EmitClearNative (class ILCodeStream *) 46 coreclr!OleVariant::MarshalCBoolVariantOleRefToCom (struct tagVARIANT *, struct VariantData *) 47 coreclr!ILMarshaler::EmitMarshalViaPinning (class ILCodeStream *) 48 coreclr!Frame::UpdateRegDisplay (struct REGDISPLAY *) 49 coreclr!LoaderAllocator::CleanupDependentHandlesToNativeObjects (void) 50 coreclr!MethodTable::MethodDataInterface::InvalidateCachedVirtualSlot (unsigned int) 51 coreclr!FrameBase::GcScanRoots (<function> *, struct ScanContext *) 52 coreclr!OleVariant::MarshalCBoolVariantComToOle (struct VariantData *, struct tagVARIANT *) 53 coreclr!EmptyApcCallback (unsigned int64) 54 coreclr!MDInternalRO::EnumMethodImplClose (struct HENUMInternal *, struct HENUMInternal *) 55 coreclr!OleVariant::MarshalWinBoolVariantOleRefToCom (struct tagVARIANT *, struct VariantData *) 56 coreclr!EEJitManager::EnumMemoryRegionsForMethodUnwindInfo (CLRDataEnumMemoryFlags, class EECodeInfo *) 57 coreclr!LoaderAllocator::CleanupHandles (void) 58 coreclr!OleVariant::MarshalWinBoolVariantComToOle (struct VariantData *, struct tagVARIANT *) 59 coreclr!block_serialize_header_func (void *, struct _FastSerializer *) 60 coreclr!OleVariant::MarshalAnsiCharVariantComToOle (struct VariantData *, struct tagVARIANT *) 61 coreclr!CrossLoaderAllocatorHash<InliningInfoTrackerHashTraits>::KeyValueStoreOrLAHashKeyToTrackers::~KeyValueStoreOrLAHashKeyToTrackers (void) 62 coreclr!JIT_LogMethodEnter (struct CORINFO_METHOD_STRUCT_ *) 63 coreclr!JIT_StressGC (void) 64 coreclr!listen_port_reset (void *, <function> *) 65 coreclr!OleVariant::MarshalAnsiCharVariantOleRefToCom (struct tagVARIANT *, struct VariantData *) 66 coreclr!_guard_check_icall_nop (unsigned int64) 67 coreclr!standalone::GCToEEInterface::UpdateGCEventStatus (int, int, int, int) 68 coreclr!OleVariant::MarshalWinBoolVariantOleToCom (struct tagVARIANT *, struct VariantData *) 69 coreclr!OleVariant::MarshalAnsiCharVariantOleToCom (struct tagVARIANT *, struct VariantData *) 70 coreclr!WKS::GCHeap::Shutdown (void) 71 coreclr!CEEInfo::classMustBeLoadedBeforeCodeIsRun (struct CORINFO_CLASS_STRUCT_ *) 72 coreclr!LCGMethodResolver::FreeCompileTimeState (void) 73 coreclr!DebuggerController::TriggerTraceCall (class Thread *, unsigned char *) 74 coreclr!Debugger::CleanupTransportSocket (void) 75 coreclr!ILMarshaler::EmitClearNativeContents (class ILCodeStream *) 76 coreclr!LoaderAllocator::RegisterHandleForCleanup (struct OBJECTHANDLE__ *) 77 coreclr!LoaderAllocator::UnregisterHandleFromCleanup (struct OBJECTHANDLE__ *) 78 coreclr!UnmanagedToManagedFrame::ExceptionUnwind (void) 79 coreclr!EEDbgInterfaceImpl::ClearAllDebugInterfaceReferences (void) 80 coreclr!ILMarshaler::EmitClearCLRContents (class ILCodeStream *) 81 coreclr!OleVariant::MarshalCBoolVariantOleToCom (struct tagVARIANT *, struct VariantData *) 82 coreclr!MethodTable::MethodDataInterface::UpdateImplMethodDesc (class MethodDesc *, unsigned int) 83 coreclr!CEEInfo::beginInlining (struct CORINFO_METHOD_STRUCT_ *, struct CORINFO_METHOD_STRUCT_ *) 84 coreclr!ILMarshaler::EmitConvertSpaceNativeToCLR (class ILCodeStream *) 85 coreclr!DispParamMarshaler::CleanUpManaged (class Object **) 86 coreclr!ILMarshaler::EmitConvertContentsNativeToCLR (class ILCodeStream *) 87 0:000>
00007ffd`0d09a548 这个地址就是 coreclr!InlinedCallFrame 的虚函数表(vftable),我们可以使用【!u 00007ffd`0d09a548】命令查看它的汇编源码。
1 0:000> !u 00007ffd`0d09a548 2 Unmanaged code 3 00007ffd`0d09a548 809ddf0cfd7f00 sbb byte ptr [rbp+7FFD0CDFh],0 4 00007ffd`0d09a54f 00909ddf0cfd add byte ptr [rax-2F32063h],dl 5 00007ffd`0d09a555 7f00 jg coreclr!InlinedCallFrame::`vftable'+0xf (00007ffd`0d09a557) 6 00007ffd`0d09a557 00809ddf0cfd add byte ptr [rax-2F32063h],al 7 00007ffd`0d09a55d 7f00 jg coreclr!InlinedCallFrame::`vftable'+0x17 (00007ffd`0d09a55f) 8 00007ffd`0d09a55f 00c0 add al,al 9 00007ffd`0d09a561 8adf mov bl,bh 10 00007ffd`0d09a563 0cfd or al,0FDh 11 00007ffd`0d09a565 7f00 jg coreclr!InlinedCallFrame::`vftable'+0x1f (00007ffd`0d09a567) 12 00007ffd`0d09a567 00e0 add al,ah
1 0:000> x kernel32!*beep* 2 00007ffd`e45b6980 KERNEL32!BeepImplementation (BeepImplementation) 3 00007ffd`e4602418 KERNEL32!_imp_Beep = <no type information>
然后我们在这个方法上下断点,通过【bp KERNEL32!BeepImplementation 】命令下断点。
1 0:000> bp KERNEL32!BeepImplementation
断点设置成功后,然后继续【g】运行调试器,会在我们设置的断点出中断执行。
1 0:000> g 2 ModLoad: 00007ffd`e6150000 00007ffd`e6182000 C:\Windows\System32\IMM32.DLL 3 ModLoad: 00007ffd`1f370000 00007ffd`1f3c9000 C:\Program Files\dotnet\host\fxr\8.0.4\hostfxr.dll 4 ModLoad: 00007ffd`0f1a0000 00007ffd`0f204000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\hostpolicy.dll 5 ModLoad: 00007ffd`0cde0000 00007ffd`0d2c6000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\coreclr.dll 6 ModLoad: 00007ffd`e4cf0000 00007ffd`e4e1b000 C:\Windows\System32\ole32.dll 7 ModLoad: 00007ffd`e4990000 00007ffd`e4ce3000 C:\Windows\System32\combase.dll 8 ModLoad: 00007ffd`e4820000 00007ffd`e48ed000 C:\Windows\System32\OLEAUT32.dll 9 ModLoad: 00007ffd`e3f80000 00007ffd`e4002000 C:\Windows\System32\bcryptPrimitives.dll 10 (2f24.4f6c): Unknown exception - code 04242420 (first chance) 11 ModLoad: 00007ffd`0bb40000 00007ffd`0c7cc000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Private.CoreLib.dll 12 ModLoad: 00007ffd`03aa0000 00007ffd`03c59000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\clrjit.dll 13 ModLoad: 00007ffd`e3b90000 00007ffd`e3ba2000 C:\Windows\System32\kernel.appcore.dll 14 ModLoad: 00000180`c62a0000 00000180`c62a8000 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_7_01\bin\Debug\net8.0\ExampleCore_7_01.dll 15 ModLoad: 00000180`c62b0000 00000180`c62be000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Runtime.dll 16 ModLoad: 00007ffd`294b0000 00007ffd`294d8000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Console.dll 17 Breakpoint 0 hit 18 KERNEL32!BeepImplementation: 19 00007ffd`e45b6980 48895c2418 mov qword ptr [rsp+18h],rbx ss:00000025`eb17e610=00000025eb17e900
红色标注的就是我们想要断住的方法。到了这里,我们看看当前的调用栈,使用【!clrstack】命令。
1 0:000> !clrstack 2 OS Thread Id: 0x4f6c (0) 3 Child SP IP Call Site 4 00000025EB17E628 00007ffde45b6980 [InlinedCallFrame: 00000025eb17e628] ExampleCore_7_01.Program.Beep(UInt32, UInt32) 5 00000025EB17E628 00007ffcad3b1a63 [InlinedCallFrame: 00000025eb17e628] ExampleCore_7_01.Program.Beep(UInt32, UInt32) 6 00000025EB17E600 00007ffcad3b1a63 ILStubClass.IL_STUB_PInvoke(UInt32, UInt32) 7 00000025EB17E6F0 00007ffcad3b1963 ExampleCore_7_01.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_7_01\Program.cs @ 13]
从【!clrstack】命令的输出可以看到,ExampleCore_7_01.Program.Main 方法正在调用 ExampleCore_7_01.Program.Beep 方法。与 ExampleCore_7_01.Program.Beep 方法对应的栈帧有着如下的前缀:[InlinedCallFrame: 00000025eb17e628]。
[InlinedCallFrame: 00000025eb17e628] 这样有一个地址,就是一个栈针,这个栈针就是 CLR 里面的部分,这个栈针地址就会调用 LoadLibrary方法,加载【Kernel32.dll】,如果加载了这个dll,就不需要在加载了,如果没有加载才加载。加载了 dll 找到 Beep 方法的方发表,调用执行就可以了。
我们可以使用【dp 00000025eb17e628】命令查看一下这个指针。
1 0:000> dp 00000025eb17e628 2 00000025`eb17e628 00007ffd`0d1da548 ffffffff`ffffffff 3 00000025`eb17e638 00007ffc`ad4600c0 00007ffc`ad4600c0 4 00000025`eb17e648 00000025`eb17e600 00007ffc`ad3b1a63 5 00000025`eb17e658 00000025`eb17e6e0 00000000`c9008e98 6 00000025`eb17e668 00007ffc`ad4600c0 00000180`c48fe920 7 00000025`eb17e678 00000000`00000000 00007ffd`e45b6980 8 00000025`eb17e688 00000000`00000000 00000000`000003e8 9 00000025`eb17e698 00000000`000003e8 00000000`00000001
00007ffd`0d1da548 这个地址像一个代码地址,因此,我们使用【ln 00007ffd`0d1da548】命令查看该地址能否被解析成代码。
1 0:000> ln 00007ffd`0d1da548 2 Browse module 3 Set bu breakpoint 4 5 (00007ffd`0d1da548) coreclr!InlinedCallFrame::`vftable' | (00007ffd`0d1da5d8) coreclr!vtable_DebuggerSecurityCodeMarkFrame 6 Exact matches: 7 coreclr!vtable_InlinedCallFrame = 0x00007ffd`0cf39d80 8 coreclr!InlinedCallFrame::`vftable' = <function> *[18]
当然,我们也可以使用【!u 00007ffd`0d1da548】命令,查看 coreclr!InlinedCallFrame 方法的源码,这个源码是汇编源码。
1 0:000> !u 00007ffd`0d1da548 2 Unmanaged code 3 00007ffd`0d1da548 809df30cfd7f00 sbb byte ptr [rbp+7FFD0CF3h],0 4 00007ffd`0d1da54f 00909df30cfd add byte ptr [rax-2F30C63h],dl 5 00007ffd`0d1da555 7f00 jg coreclr!InlinedCallFrame::`vftable'+0xf (00007ffd`0d1da557) 6 00007ffd`0d1da557 00809df30cfd add byte ptr [rax-2F30C63h],al 7 00007ffd`0d1da55d 7f00 jg coreclr!InlinedCallFrame::`vftable'+0x17 (00007ffd`0d1da55f) 8 00007ffd`0d1da55f 00c0 add al,al 9 00007ffd`0d1da561 8af3 mov dh,bl 10 00007ffd`0d1da563 0cfd or al,0FDh 11 00007ffd`0d1da565 7f00 jg coreclr!InlinedCallFrame::`vftable'+0x1f (00007ffd`0d1da567) 12 00007ffd`0d1da567 00e0 add al,ah
输出信息表明这个地址对应于对象 InlinedCallFrame 的虚函数表。我们可以进一步将虚函数表转储出来,执行命令【dp 00007ffd`0d1da548 l4】。
0:000> dp 00007ffd`0d1da548 l4 00007ffd`0d1da548 00007ffd`0cf39d80 00007ffd`0cf39d90 00007ffd`0d1da558 00007ffd`0cf39d80 00007ffd`0cf38ac0
00007ffd`0cf39d80 并在这个函数地址上使用【ln 00007ffd`0cf39d80】命令来观察它所包含的内容。
1 0:000> ln 00007ffd`0cf39d80 2 Browse module 3 Set bu breakpoint 4 5 [D:\a\_work\1\s\src\coreclr\inc\utilcode.h @ 417] SrcSrv Command: https://raw.githubusercontent.com/dotnet/runtime/2d7eea252964e69be94cb9c847b371b23e4dd470/src/coreclr/inc/utilcode.h 6 (00007ffd`0cf39d80) coreclr!LoaderAllocator::CleanupDependentHandlesToNativeObjects | (00007ffd`0cf39d90) coreclr!BaseDomain::IsAppDomain 7 Exact matches: 8 coreclr!DebuggerController::TriggerFuncEvalExit (class Thread *) 9 coreclr!standalone::GCToEEInterface::WalkAsyncPinnedForPromotion (class Object *, struct ScanContext *, <function> *) 10 coreclr!DispatchStubState::SetLastError (int) 11 coreclr!BINDER_SPACE::AssemblyVersion::~AssemblyVersion (void) 12 coreclr!ThreadDebugBlockingInfo::~ThreadDebugBlockingInfo (void) 13 coreclr!StubCacheBase::AddStub (unsigned char *, class Stub *) 14 coreclr!DispatchStubState::MarshalLCID (int) 15 coreclr!JIT_DebugLogLoopCloning (void) 16 coreclr!SVR::GCHeap::Shutdown (void) 17 coreclr!LoaderAllocator::UnregisterDependentHandleToNativeObjectFromCleanup (class LADependentHandleToNativeObject *) 18 coreclr!DispatchStubState::MarshalReturn (class MarshalInfo *, int) 19 coreclr!StgPoolSeg::~StgPoolSeg (void) 20 coreclr!noncopyable::~noncopyable (void) 21 coreclr!standalone::GCToEEInterface::WalkAsyncPinned (class Object *, void *, <function> *) 22 coreclr!HashMap::Iterator::~Iterator (void) 23 coreclr!standalone::GCToEEInterface::SyncBlockCachePromotionsGranted (int) 24 coreclr!EEClass::~EEClass (void) 25 coreclr!ILMarshaler::EmitCreateMngdMarshaler (class ILCodeStream *) 26 coreclr!ILMarshaler::EmitClearCLR (class ILCodeStream *) 27 coreclr!CEEInfo::methodMustBeLoadedBeforeCodeIsRun (struct CORINFO_METHOD_STRUCT_ *) 28 coreclr!LADependentNativeObject::~LADependentNativeObject (void) 29 coreclr!CEEJitInfo::recordCallSite (unsigned int, struct CORINFO_SIG_INFO *, struct CORINFO_METHOD_STRUCT_ *) 30 coreclr!Frame::ExceptionUnwind (void) 31 coreclr!EEDbgInterfaceImpl::ClearThreadException (class Thread *) 32 coreclr!MethodTable::MethodDataInterfaceImpl::UpdateImplMethodDesc (class MethodDesc *, unsigned int) 33 coreclr!DebuggerController::TriggerMethodEnter (class Thread *, class DebuggerJitInfo *, unsigned char *, class FramePointer) 34 coreclr!DebuggerController::TriggerUnwind (class Thread *, class MethodDesc *, class DebuggerJitInfo *, unsigned int64, class FramePointer, CorDebugStepReason) 35 coreclr!DebuggerController::DebuggerDetachClean (void) 36 coreclr!LoaderAllocator::RegisterDependentHandleToNativeObjectForCleanup (class LADependentHandleToNativeObject *) 37 coreclr!ComPrestubMethodFrame::ExceptionUnwind (void) 38 coreclr!EEDbgInterfaceImpl::DebuggerModifyingLogSwitch (int, wchar_t *) 39 coreclr!CEEInfo::updateEntryPointForTailCall (struct CORINFO_CONST_LOOKUP *) 40 coreclr!ILMarshaler::EmitConvertSpaceCLRToNative (class ILCodeStream *) 41 coreclr!EETypeHashTable::Iterator::~Iterator (void) 42 coreclr!InstMethodHashTable::Iterator::~Iterator (void) 43 coreclr!LoaderAllocator::ReleaseManagedAssemblyLoadContext (void) 44 coreclr!ILMarshaler::EmitConvertContentsCLRToNative (class ILCodeStream *) 45 coreclr!DebuggerController::TriggerFuncEvalEnter (class Thread *) 46 coreclr!CrossLoaderAllocatorHash<MethodDescBackpatchInfoTracker::BackpatchInfoTrackerHashTraits>::KeyValueStoreOrLAHashKeyToTrackers::~KeyValueStoreOrLAHashKeyToTrackers (void) 47 coreclr!PtrHashMap::PtrIterator::~PtrIterator (void) 48 coreclr!ILMarshaler::EmitSetupArgumentForMarshalling (class ILCodeStream *) 49 coreclr!ILMarshaler::EmitClearNative (class ILCodeStream *) 50 coreclr!OleVariant::MarshalCBoolVariantOleRefToCom (struct tagVARIANT *, struct VariantData *) 51 coreclr!ILMarshaler::EmitMarshalViaPinning (class ILCodeStream *) 52 coreclr!Frame::UpdateRegDisplay (struct REGDISPLAY *) 53 coreclr!LoaderAllocator::CleanupDependentHandlesToNativeObjects (void) 54 coreclr!MethodTable::MethodDataInterface::InvalidateCachedVirtualSlot (unsigned int) 55 coreclr!FrameBase::GcScanRoots (<function> *, struct ScanContext *) 56 coreclr!OleVariant::MarshalCBoolVariantComToOle (struct VariantData *, struct tagVARIANT *) 57 coreclr!EmptyApcCallback (unsigned int64) 58 coreclr!MDInternalRO::EnumMethodImplClose (struct HENUMInternal *, struct HENUMInternal *) 59 coreclr!OleVariant::MarshalWinBoolVariantOleRefToCom (struct tagVARIANT *, struct VariantData *) 60 coreclr!EEJitManager::EnumMemoryRegionsForMethodUnwindInfo (CLRDataEnumMemoryFlags, class EECodeInfo *) 61 coreclr!LoaderAllocator::CleanupHandles (void) 62 coreclr!OleVariant::MarshalWinBoolVariantComToOle (struct VariantData *, struct tagVARIANT *) 63 coreclr!block_serialize_header_func (void *, struct _FastSerializer *) 64 coreclr!OleVariant::MarshalAnsiCharVariantComToOle (struct VariantData *, struct tagVARIANT *) 65 coreclr!CrossLoaderAllocatorHash<InliningInfoTrackerHashTraits>::KeyValueStoreOrLAHashKeyToTrackers::~KeyValueStoreOrLAHashKeyToTrackers (void) 66 coreclr!JIT_LogMethodEnter (struct CORINFO_METHOD_STRUCT_ *) 67 coreclr!JIT_StressGC (void) 68 coreclr!listen_port_reset (void *, <function> *) 69 coreclr!OleVariant::MarshalAnsiCharVariantOleRefToCom (struct tagVARIANT *, struct VariantData *) 70 coreclr!_guard_check_icall_nop (unsigned int64) 71 coreclr!standalone::GCToEEInterface::UpdateGCEventStatus (int, int, int, int) 72 coreclr!OleVariant::MarshalWinBoolVariantOleToCom (struct tagVARIANT *, struct VariantData *) 73 coreclr!OleVariant::MarshalAnsiCharVariantOleToCom (struct tagVARIANT *, struct VariantData *) 74 coreclr!WKS::GCHeap::Shutdown (void) 75 coreclr!CEEInfo::classMustBeLoadedBeforeCodeIsRun (struct CORINFO_CLASS_STRUCT_ *) 76 coreclr!LCGMethodResolver::FreeCompileTimeState (void) 77 coreclr!DebuggerController::TriggerTraceCall (class Thread *, unsigned char *) 78 coreclr!Debugger::CleanupTransportSocket (void) 79 coreclr!ILMarshaler::EmitClearNativeContents (class ILCodeStream *) 80 coreclr!LoaderAllocator::RegisterHandleForCleanup (struct OBJECTHANDLE__ *) 81 coreclr!LoaderAllocator::UnregisterHandleFromCleanup (struct OBJECTHANDLE__ *) 82 coreclr!UnmanagedToManagedFrame::ExceptionUnwind (void) 83 coreclr!EEDbgInterfaceImpl::ClearAllDebugInterfaceReferences (void) 84 coreclr!ILMarshaler::EmitClearCLRContents (class ILCodeStream *) 85 coreclr!OleVariant::MarshalCBoolVariantOleToCom (struct tagVARIANT *, struct VariantData *) 86 coreclr!MethodTable::MethodDataInterface::UpdateImplMethodDesc (class MethodDesc *, unsigned int) 87 coreclr!CEEInfo::beginInlining (struct CORINFO_METHOD_STRUCT_ *, struct CORINFO_METHOD_STRUCT_ *) 88 coreclr!ILMarshaler::EmitConvertSpaceNativeToCLR (class ILCodeStream *) 89 coreclr!DispParamMarshaler::CleanUpManaged (class Object **) 90 coreclr!ILMarshaler::EmitConvertContentsNativeToCLR (class ILCodeStream *)
不是很难,就不多做解释了。
如图所示,首先是托管客户端调用 COM 对象中定义的方法,该对象是在 PIA 中定义的。CLR 通过来自 PIA 的信息创建 RCW 的实例。然后,RCW 截获对这个方法的调用,将参数转换为非托管类型,切换环境,并且调用非托管代码中的方法。
RCW 另外一个功能负责处理底层 COM 对象的生命周期。COM 对象的生命周期是通过一种引用计数模式来管理的,这就意味着每当获取对象的一个接口时,引用计数就会增加。相反,当不在需要一个接口时,引用计数就会递减。当引用计数为 0 时,就可以销毁对象了。RCW 能跟踪引用的数量,并确保相应的递增/递减引用计数。当托管客户端使用完 RCW 并且不存在未释放的引用后, RCW 会被回收,并且相关的 COM 对象都会被释放。
RCW 有两种释放的方式:第一种,当不存在对 RCW 的引用后,RCW 会递减并且清除对底层 COM 对象的任何引用,因而 COM 对象直到垃圾收集器清除时才会被清除。第二种,我们可以使用 Marshal.ReleaseComObject 方法强制释放 COM 对象。
有一些 SOS 命令可以获取 COM 互用性相关的信息。
【!t】或者【!threads】命令获取所有托管线程的信息,其中就包含【套间】类型的信息。【套间】是一种逻辑结构,与 COM 线程模型紧密相关。如果某个 COM 组件的编写不考虑并发调用的情况,就可以使用单线程套间(STA),这种套间会使 COM 子系统对所有这个组件的调用串行化。相反,如果能够处理并发调用的组件就可以使用多线程套间(MTA)模型,在这种情况下,针对组件的访问就不需要串行化。
当任何一个线程使用 COM 组件时,它必须选择合适的套间模型。在默认的情况下,所有的 .NET 线程都在 MTA 模型中。
我们来一张图直观的感受一下【!t】命令的结果,如图:
【!syncblk】命令也可以输出与 COM 互用性相关的信息,如图:
在该命令的输出中给出了 CLR 已经实例化的并且当前处于活跃状态的 RCW 的数量。当想快速了解当前 RCW 的使用情况时,这个命令很有用。
【!COMState】命令能够对进程中的每个线程输出 COM 的详细信息。效果如图:
1 0:000> g 2 ModLoad: 00007ff9`c1140000 00007ff9`c1172000 C:\Windows\System32\IMM32.DLL 3 ModLoad: 00007ff9`36e00000 00007ff9`36e59000 C:\Program Files\dotnet\host\fxr\8.0.4\hostfxr.dll 4 ModLoad: 00007ff9`0a5f0000 00007ff9`0a654000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\hostpolicy.dll 5 ModLoad: 00007ff8`f5c40000 00007ff8`f6126000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\coreclr.dll 6 ModLoad: 00007ff9`c2630000 00007ff9`c275b000 C:\Windows\System32\ole32.dll 7 ModLoad: 00007ff9`c13e0000 00007ff9`c1733000 C:\Windows\System32\combase.dll 8 ModLoad: 00007ff9`c1740000 00007ff9`c180d000 C:\Windows\System32\OLEAUT32.dll 9 ModLoad: 00007ff9`c0730000 00007ff9`c07b2000 C:\Windows\System32\bcryptPrimitives.dll 10 (fa0.1cf0): Unknown exception - code 04242420 (first chance) 11 ModLoad: 00007ff8`f4d70000 00007ff8`f59fc000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Private.CoreLib.dll 12 ModLoad: 00007ff8`f4bb0000 00007ff8`f4d69000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\clrjit.dll 13 ModLoad: 00007ff9`c0f10000 00007ff9`c0f22000 C:\Windows\System32\kernel.appcore.dll 14 ModLoad: 00000110`f1e80000 00000110`f1e88000 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_7_02\bin\Debug\net8.0\ExampleCore_7_02.dll 15 ModLoad: 00000110`f1e90000 00000110`f1e9e000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Runtime.dll 16 ModLoad: 00007ff9`9bfa0000 00007ff9`9bfc8000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Console.dll 17 (fa0.1cf0): C++ EH exception - code e06d7363 (first chance) 18 ModLoad: 00007ff9`8c330000 00007ff9`8c55e000 C:\Windows\SYSTEM32\icu.dll 19 (fa0.1cf0): CLR exception - code e0434352 (first chance) 20 (fa0.1cf0): CLR exception - code e0434352 (!!! second chance !!!) 21 KERNELBASE!RaiseException+0x69: 22 00007ff9`c07ecf19 0f1f440000 nop dword ptr [rax+rax]
原著中说的是抛出“访问违例”的异常,我这里是没有看到,只是看到了内核态抛出了异常。
我按着原书的步骤来,如果我们想获取是哪行源代码出问题了,可以使用【!lines】命令
1 0:000> !lines 2 Line number information will be loaded
我们再使用【!clrstack】命令,查看一下托管线程调用栈,源代码的行号就会显示出来。
1 0:000> !clrstack 2 OS Thread Id: 0x1cf0 (0) 3 Child SP IP Call Site 4 000000031FB7E548 00007ff9c07ecf19 [PrestubMethodFrame: 000000031fb7e548] ExampleCore_7_02.Program.Alloc(System.String) 5 000000031FB7E720 00007FF89624196E ExampleCore_7_02.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_7_02\Program.cs @ 13]
ExampleCore_7_02.Program.Main 栈帧的内容最后有一个数字 13,这个就是源代码的行号,出错的行号。
效果如图:
最开始的时候,我们的调试器抛出异常,有一个地址 00007ff9`c07ecf19 ,这个地址就是错误代码,可以使用【!u 00007ff9`c07ecf19】命令查看代码的内容。
1 0:000> !u 00007ff9`c07ecf19 2 Unmanaged code 3 00007ff9`c07ecf19 0f1f440000 nop dword ptr [rax+rax] 4 00007ff9`c07ecf1e 488b8c24c0000000 mov rcx,qword ptr [rsp+0C0h] 5 00007ff9`c07ecf26 4833cc xor rcx,rsp 6 00007ff9`c07ecf29 e8f2880600 call KERNELBASE!_security_check_cookie (00007ff9`c0855820) 7 00007ff9`c07ecf2e 4881c4d8000000 add rsp,0D8h 8 00007ff9`c07ecf35 c3 ret 9 00007ff9`c07ecf36 cc int 3 10 00007ff9`c07ecf37 8364243800 and dword ptr [rsp+38h],0 11 00007ff9`c07ecf3c ebcf jmp KERNELBASE!RaiseException+0x5d (00007ff9`c07ecf0d) 12 00007ff9`c07ecf3e cc int 3
就是抛出异常的代码。
1 0:000> g 2 ModLoad: 00007fff`50700000 00007fff`50732000 C:\Windows\System32\IMM32.DLL 3 ModLoad: 00007ffe`567c0000 00007ffe`56819000 C:\Program Files\dotnet\host\fxr\8.0.4\hostfxr.dll 4 ModLoad: 00007ffe`56750000 00007ffe`567b4000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\hostpolicy.dll 5 ModLoad: 00007ffe`56260000 00007ffe`56746000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\coreclr.dll 6 ModLoad: 00007fff`52120000 00007fff`5224b000 C:\Windows\System32\ole32.dll 7 ModLoad: 00007fff`52380000 00007fff`526d3000 C:\Windows\System32\combase.dll 8 ModLoad: 00007fff`50e10000 00007fff`50edd000 C:\Windows\System32\OLEAUT32.dll 9 ModLoad: 00007fff`50350000 00007fff`503d2000 C:\Windows\System32\bcryptPrimitives.dll 10 (25fc.9f0): Unknown exception - code 04242420 (first chance) 11 ModLoad: 00007ffe`550d0000 00007ffe`55d5c000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Private.CoreLib.dll 12 ModLoad: 00007ffe`54f10000 00007ffe`550c9000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\clrjit.dll 13 ModLoad: 00007fff`506e0000 00007fff`506f2000 C:\Windows\System32\kernel.appcore.dll 14 ModLoad: 000001f6`83a80000 000001f6`83a88000 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_7_02\bin\Debug\net8.0\ExampleCore_7_02.dll 15 ModLoad: 000001f6`83a90000 000001f6`83a9e000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Runtime.dll 16 ModLoad: 00007ffe`54ee0000 00007ffe`54f08000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Console.dll 17 (25fc.9f0): C++ EH exception - code e06d7363 (first chance) 18 ModLoad: 00007fff`1a810000 00007fff`1aa3e000 C:\Windows\SYSTEM32\icu.dll 19 (25fc.9f0): CLR exception - code e0434352 (first chance) 20 (25fc.9f0): CLR exception - code e0434352 (!!! second chance !!!) 21 KERNELBASE!RaiseException+0x69: 22 00007fff`4fbfcf19 0f1f440000 nop dword ptr [rax+rax]
原书上说的是出现了异常,原因是访问违例,这里不是的,这么多年了,变化也不小。
我按着原书的步骤来,如果我们想获取是哪行源代码出问题了,可以使用【!lines】命令。
1 0:000> !lines 2 Line number information will not be loaded
其实,在【Windbg Preview】里面不需要使用这个命令。原书的内容是使用了【k】命令,其实作用不大,我们其实可以直接使用【!clrstack】命令,看得更直接。
1 0:000> !clrstack 2 OS Thread Id: 0x9f0 (0) 3 Child SP IP Call Site 4 000000338C57E528 00007fff4fbfcf19 [PrestubMethodFrame: 000000338c57e528] ExampleCore_7_02.Program.Alloc(System.String) 5 000000338C57E700 00007ffdf687196e ExampleCore_7_02.Program.Main(System.String[])
托管线程的调用栈很清楚,就不多说了。我们可以使用【!u 00007fff4fbfcf19】查看一下这个地址的代码是什么。
1 0:000> !u 00007fff4fbfcf19 2 Unmanaged code 3 00007fff`4fbfcf19 0f1f440000 nop dword ptr [rax+rax] 4 00007fff`4fbfcf1e 488b8c24c0000000 mov rcx,qword ptr [rsp+0C0h] 5 00007fff`4fbfcf26 4833cc xor rcx,rsp 6 00007fff`4fbfcf29 e8f2880600 call KERNELBASE!_security_check_cookie (00007fff`4fc65820) 7 00007fff`4fbfcf2e 4881c4d8000000 add rsp,0D8h 8 00007fff`4fbfcf35 c3 ret 9 00007fff`4fbfcf36 cc int 3 10 00007fff`4fbfcf37 8364243800 and dword ptr [rsp+38h],0 11 00007fff`4fbfcf3c ebcf jmp KERNELBASE!RaiseException+0x5d (00007fff`4fbfcf0d) 12 00007fff`4fbfcf3e cc int 3
KERNELBASE!RaiseException 内核抛出的异常。
1 0:000> bp ExampleCore_7_03!AsyncProcess 2 Bp expression 'ExampleCore_7_03!AsyncProcess' could not be resolved, adding deferred bp
那我们就通过源码的方式直接给 C++ AsyncProcess 方法下断点。我们点击 Windbg 菜单栏,依次选择【Source】--->【Open Source File】,打开选择我们的 C++ 项目中的 ExampleCore_7_033.cpp 文件。效果如图:
断点设置完成后,我们直接执行【g】命令,继续运行调试器。效果如图:
【Windbg Preview】命令窗口展示如图:
执行效果如下:
1 0:000> bl 2 0 e Disable Clear u 0001 (0001) (@@masm(`E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_7_033\ExampleCore_7_033.cpp:28+`)) 3 4 0:000> g 5 ModLoad: 0000026d`613d0000 0000026d`613de000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Runtime.dll 6 ModLoad: 00007ff8`0d190000 00007ff8`0d1b8000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Console.dll 7 *** WARNING: Unable to verify checksum for E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_7_03\bin\Debug\net8.0\ExampleCore_7_033.DLL 8 ModLoad: 00007ff8`0c490000 00007ff8`0c4b6000 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_7_03\bin\Debug\net8.0\ExampleCore_7_033.DLL 9 ModLoad: 00007ff8`499a0000 00007ff8`499ce000 C:\Windows\SYSTEM32\VCRUNTIME140D.dll 10 ModLoad: 00007fff`b9560000 00007fff`b9781000 C:\Windows\SYSTEM32\ucrtbased.dll 11 Breakpoint 0 hit 12 ExampleCore_7_033!AsyncProcess+0x1f:(断点处) 13 00007ff8`0c4a17ff 48c744242800000000 mov qword ptr [rsp+28h],0 ss:000000d7`5a97e328={coreclr!HelperMethodFrame_1OBJ::`vftable' (00007fff`9dfc9d08)}
我们继续执行【dv】命令,可以看到有一个 ptr,那就是我们从托管代码中传递到非托管代码中的委托,就是一个指针。
1 0:000> dv 2 ptr = 0x00007fff`3e063024 3 hThread = 0x00007fff`9dfc9af8
【ptr】这个字段在【Windbg Preview】里是可以点击的,如果是命令行调试就不可以了,比如:NTSD 等。如图:
我们可以使用【u 0x00007fff`3e063024】命令,查看一下这个 ptr 是什么。
1 0:000> u 7fff3e063024 2 00007fff`3e063024 49ba0030063eff7f0000 mov r10,7FFF3E063000h 3 00007fff`3e06302e 48b8d0d0d29dff7f0000 mov rax,offset coreclr!TheUMEntryPrestub (00007fff`9dd2d0d0) 4 00007fff`3e063038 48ffe0 jmp rax 5 00007fff`3e06303b 0000 add byte ptr [rax],al 6 00007fff`3e06303d 0000 add byte ptr [rax],al 7 00007fff`3e06303f 0000 add byte ptr [rax],al 8 00007fff`3e063041 0000 add byte ptr [rax],al 9 00007fff`3e063043 0000 add byte ptr [rax],al
我们在【PCallback callback = (PCallback)lpParameter;】这行代码在下一个断点,也就是2秒后会执行这个回调。效果如图:
断点设置成功后,我们继续执行调试器,使用【g】命令。
1 0:000> g 2 ModLoad: 00007ff8`6fd70000 00007ff8`6fd82000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Threading.dll 3 ModLoad: 0000026d`61400000 0000026d`61408000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Text.Encoding.Extensions.dll 4 ModLoad: 00007ff8`6fd50000 00007ff8`6fd65000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Runtime.InteropServices.dll 5 Breakpoint 1 hit 6 ExampleCore_7_033!ThreadWorkItem+0x3e:(成功断住) 7 00007ff8`0c4a172e 488b8500010000 mov rax,qword ptr [rbp+100h] ss:000000d7`5b6ffec0=00007fff3e063024
如图:
到了这里,我们在使用【u 0x00007fff`3e063024】命令,查看一下这个 ptr 是什么东西。
1 0:009> u 0x00007fff`3e063024 2 00007fff`3e063024 49ba0030063eff7f0000 mov r10,7FFF3E063000h 3 00007fff`3e06302e 48b8d0d0d29dff7f0000 mov rax,offset coreclr!TheUMEntryPrestub (00007fff`9dd2d0d0) 4 00007fff`3e063038 48ffe0 jmp rax 5 00007fff`3e06303b 0000 add byte ptr [rax],al 6 00007fff`3e06303d 0000 add byte ptr [rax],al 7 00007fff`3e06303f 0000 add byte ptr [rax],al 8 00007fff`3e063041 0000 add byte ptr [rax],al 9 00007fff`3e063043 0000 add byte ptr [rax],al
我在 .NET Framework 版本中,此时【ptr】已经是坏的数据了。效果如图:
都是乱码了,都是 ??? 问号了,就是说 ptr 不存在了,说明已经被我们 GC 回收了。但是在 .NET 8.0 数据还是存在的,也许是改进了,具体原因我还没有搞清楚。
如果遇到这样的情况,我们怎么解决呢?其实很简单,在我们的 C# 代码中,声明一个静态的 handle 就可以了,如:static GCHandle handle;在我的代码中,注释的部分就是解决办法。
我们可以看到,随着迭代次数的增加,所使用的内存也是递增的。在最后一次迭代(一百万次)中,内存尽然使用了 477.2 MB,说明程序在使用内存出现了问题,这就是问题的表现,接下来我们尝试解决一下。
然后,我们输入 1000000,回车继续执行,直到调试器输出“Press any key to exit!”字样,调试器暂停。如图:
此时,我们打开【任务管理器】,查看一下我们的项目运行占用多少内存,如图:
回到调试器,点击组合键【ctrl+c】进入中断模式,开始我们的调试吧。
我们先使用【!eeheap -loader】命令看看加载堆上是否存在异常。
1 0:002> !eeheap -loader 2 Loader Heap: 3 -------------------------------------- 4 System Domain: 00007ff9c23140c0 5 LowFrequencyHeap: 00007FF9625C0000(10000:e000) 00007FF962550000(10000:10000) 00007FF962520000(10000:10000) 00007FF962450000(10000:10000) 00007FF9623F0000(10000:10000) 00007FF962350000(70000:70000) 00007FF962330000(3000:1000) Size: 0xbf000 (782336) bytes total, 0x2000 (8192) bytes wasted. 6 HighFrequencyHeap: 00007FF962620000(10000:2000) 00007FF9625F0000(10000:10000) 00007FF9625D0000(10000:10000) 00007FF962590000(10000:10000) 00007FF962570000(10000:10000) 00007FF962540000(10000:10000) 00007FF962510000(10000:10000) 00007FF962470000(10000:10000) 00007FF962440000(10000:10000) 00007FF962420000(10000:10000) 00007FF962400000(10000:10000) 00007FF9623C0000(10000:10000) 00007FF962334000(9000:6000) Size: 0xb8000 (753664) bytes total, 0x3000 (12288) bytes wasted. 7 StubHeap: Size: 0x0 (0) bytes. 8 Virtual Call Stub Heap: 9 IndcellHeap: 00007FF962340000(6000:1000) Size: 0x1000 (4096) bytes. 10 LookupHeap: Size: 0x0 (0) bytes. 11 ResolveHeap: Size: 0x0 (0) bytes. 12 DispatchHeap: Size: 0x0 (0) bytes. 13 CacheEntryHeap: Size: 0x0 (0) bytes. 14 Total size: Size: 0x178000 (1540096) bytes total, 0x5000 (20480) bytes wasted. 15 -------------------------------------- 16 Domain 1: 00000201b777ee80 17 LowFrequencyHeap: 00007FF9625C0000(10000:e000) 00007FF962550000(10000:10000) 00007FF962520000(10000:10000) 00007FF962450000(10000:10000) 00007FF9623F0000(10000:10000) 00007FF962350000(70000:70000) 00007FF962330000(3000:1000) Size: 0xbf000 (782336) bytes total, 0x2000 (8192) bytes wasted. 18 HighFrequencyHeap: 00007FF962620000(10000:2000) 00007FF9625F0000(10000:10000) 00007FF9625D0000(10000:10000) 00007FF962590000(10000:10000) 00007FF962570000(10000:10000) 00007FF962540000(10000:10000) 00007FF962510000(10000:10000) 00007FF962470000(10000:10000) 00007FF962440000(10000:10000) 00007FF962420000(10000:10000) 00007FF962400000(10000:10000) 00007FF9623C0000(10000:10000) 00007FF962334000(9000:6000) Size: 0xb8000 (753664) bytes total, 0x3000 (12288) bytes wasted. 19 StubHeap: Size: 0x0 (0) bytes. 20 Virtual Call Stub Heap: 21 IndcellHeap: 00007FF962340000(6000:1000) Size: 0x1000 (4096) bytes. 22 LookupHeap: Size: 0x0 (0) bytes. 23 ResolveHeap: Size: 0x0 (0) bytes. 24 DispatchHeap: Size: 0x0 (0) bytes. 25 CacheEntryHeap: Size: 0x0 (0) bytes. 26 Total size: Size: 0x178000 (1540096) bytes total, 0x5000 (20480) bytes wasted. 27 -------------------------------------- 28 Jit code heap: 29 LoaderCodeHeap: 0000000000000000(0:0) Size: 0x0 (0) bytes. 30 Total size: Size: 0x0 (0) bytes. 31 -------------------------------------- 32 Module Thunk heaps: 33 Module 00007ff962334000: Size: 0x0 (0) bytes. 34 Module 00007ff96251e0a0: Size: 0x0 (0) bytes. 35 Module 00007ff96251fbc8: Size: 0x0 (0) bytes. 36 Module 00007ff96254a268: Size: 0x0 (0) bytes. 37 Module 00007ff96254c020: Size: 0x0 (0) bytes. 38 Module 00007ff962572108: Size: 0x0 (0) bytes. 39 Module 00007ff9625745e0: Size: 0x0 (0) bytes. 40 Total size: Size: 0x0 (0) bytes. 41 -------------------------------------- 42 Module Lookup Table heaps: 43 Module 00007ff962334000: 0000000000000008(0:0) 0000000000000000(0:0) Size: 0x0 (0) bytes. 44 Module 00007ff96251e0a0: 0000000000000008(0:0) 0000000000000000(0:0) Size: 0x0 (0) bytes. 45 Module 00007ff96251fbc8: 0000000000000008(0:0) 0000000000000000(0:0) Size: 0x0 (0) bytes. 46 Module 00007ff96254a268: 0000000000000008(0:0) 0000000000000000(0:0) Size: 0x0 (0) bytes. 47 Module 00007ff96254c020: 0000000000000008(0:0) 0000000000000000(0:0) Size: 0x0 (0) bytes. 48 Module 00007ff962572108: 0000000000000008(0:0) 0000000000000000(0:0) Size: 0x0 (0) bytes. 49 Module 00007ff9625745e0: 0000000000000008(0:0) 0000000000000000(0:0) Size: 0x0 (0) bytes. 50 Total size: Size: 0x0 (0) bytes. 51 -------------------------------------- 52 Total LoaderHeap size: Size: 0x2f0000 (3080192) bytes total, 0xa000 (40960) bytes wasted. 53 ======================================= 54 0:002>
无论是系统域还是私有域,内存使用量都是 1.5 MB ,和 492.8 MB 差的太远了,说明加载堆没异常。
我们继续使用【!eeheap -gc】命令查看一下 GC 堆是否有问题。
1 0:002> !eeheap -gc 2 Number of GC Heaps: 1 3 generation 0 starts at 0x00000201BB400028 4 generation 1 starts at 0x00000201BBC00028 5 generation 2 starts at 0x000002424DED0008 6 ephemeral segment allocation context: none 7 segment begin allocated committed allocated size committed size 8 generation 0: 9 00000241CD3CF1C0 00000201BB400028 00000201BB400028 00000201BB421000 0x0(0) 0x20fd8(135128) 10 generation 1: 11 00000241CD3CF320 00000201BBC00028 00000201BBC141E8 00000201BBC21000 0x141c0(82368) 0x20fd8(135128) 12 generation 2: 13 00000201B7761B20 000002424DED0008 000002424DED1BE8 000002424DEE0000 0x1be0(7136) 0xfff8(65528) 14 00000241CD3CF950 00000201BE000028 00000201BE000028 00000201BE001000 0x0(0) 0xfd8(4056) 15 Large object heap starts at 0x0000000000000000 16 segment begin allocated committed allocated size committed size 17 00000241CD3CF3D0 00000201BC000028 00000201BC000028 00000201BC001000 0x0(0) 0xfd8(4056) 18 Pinned object heap starts at 0x0000000000000000 19 00000241CD3CEC40 00000201B9400028 00000201B9404018 00000201B9411000 0x3ff0(16368) 0x10fd8(69592) 20 Total Allocated Size: Size: 0x19d90 (105872) bytes. 21 Total Committed Size: Size: 0x53f58 (343896) bytes. 22 ------------------------------ 23 GC Allocated Heap Size: Size: 0x19d90 (105872) bytes. 24 GC Committed Heap Size: Size: 0x53f58 (343896) bytes. 25 0:002>
GC 堆的内容也不是很大,所以就不是托管堆的问题。
我们使用【!address -summary】命令查看一下进程整体的内存使用情况。
1 0:002> !address -summary 2 3 4 Mapping file section regions... 5 Mapping module regions... 6 Mapping PEB regions... 7 Mapping TEB and stack regions... 8 Mapping heap regions... 9 Mapping page heap regions... 10 Mapping other regions... 11 Mapping stack trace database regions... 12 Mapping activation context regions... 13 14 --- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal 15 Free 66 7dbe`41e6b000 ( 125.743 TB) 98.24% 16 MappedFile 161 200`0351a000 ( 2.000 TB) 88.62% 1.56% 17 <unknown> 82 41`97314000 ( 262.362 GB) 11.35% 0.20% 18 Heap 44 0`1fa49000 ( 506.285 MB) 0.02% 0.00% 19 Image 240 0`03422000 ( 52.133 MB) 0.00% 0.00% 20 Stack 18 0`00900000 ( 9.000 MB) 0.00% 0.00% 21 Other 8 0`001dd000 ( 1.863 MB) 0.00% 0.00% 22 TEB 6 0`0000e000 ( 56.000 kB) 0.00% 0.00% 23 PEB 1 0`00001000 ( 4.000 kB) 0.00% 0.00% 24 25 --- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal 26 MEM_MAPPED 168 200`03705000 ( 2.000 TB) 88.62% 1.56% 27 MEM_PRIVATE 152 41`b765e000 ( 262.866 GB) 11.37% 0.20% 28 MEM_IMAGE 240 0`03422000 ( 52.133 MB) 0.00% 0.00% 29 30 --- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal 31 MEM_FREE 66 7dbe`41e6b000 ( 125.743 TB) 98.24% 32 MEM_RESERVE 103 241`95f22000 ( 2.256 TB) 99.97% 1.76% 33 MEM_COMMIT 457 0`28263000 ( 642.387 MB) 0.03% 0.00% 34 35 --- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal 36 PAGE_READWRITE 174 0`1ee61000 ( 494.379 MB) 0.02% 0.00% 37 PAGE_NOACCESS 23 0`0410c000 ( 65.047 MB) 0.00% 0.00% 38 PAGE_READONLY 158 0`02b64000 ( 43.391 MB) 0.00% 0.00% 39 PAGE_EXECUTE_READ 63 0`026ea000 ( 38.914 MB) 0.00% 0.00% 40 PAGE_WRITECOPY 30 0`0007f000 ( 508.000 kB) 0.00% 0.00% 41 PAGE_READWRITE | PAGE_GUARD 7 0`00017000 ( 92.000 kB) 0.00% 0.00% 42 PAGE_EXECUTE_WRITECOPY 1 0`00010000 ( 64.000 kB) 0.00% 0.00% 43 PAGE_EXECUTE_READWRITE 1 0`00002000 ( 8.000 kB) 0.00% 0.00% 44 45 --- Largest Region by Usage ----------- Base Address -------- Region Size ---------- 46 Free 242`6f510000 7bb2`723d0000 ( 123.697 TB) 47 MappedFile 7dfe`ece65000 1f6`d66c9000 ( 1.964 TB) 48 <unknown> 201`be001000 3f`fb39f000 ( 255.925 GB) 49 Heap 242`50ae0000 0`00fcf000 ( 15.809 MB) 50 Image 7ff9`c0fb1000 0`00bfe000 ( 11.992 MB) 51 Stack 93`e7500000 0`0017c000 ( 1.484 MB) 52 Other 201`b7ac0000 0`00181000 ( 1.504 MB) 53 TEB 93`e71c9000 0`00004000 ( 16.000 kB) 54 PEB 93`e71b2000 0`00001000 ( 4.000 kB) 55 56 0:002>
红色标注的和我们 492.8 MB 的内存使用差不多,为什么会在非托管堆上呢,由此,我们可以联想到是和 P/Invoke 调用相关的,于是,我们在检查代码,找出问题。
2)、Windbg Preview 调试
1 0:001> !eeheap -loader 2 Loader Heap: 3 ---------------------------------------- 4 System Domain: 7ff9951d40c0 5 LoaderAllocator: 7ff9951d40c0 6 LowFrequencyHeap: 7ff935460000(10000:e000) 7ff9353f0000(10000:10000) 7ff9353c0000(10000:10000) 7ff9352f0000(10000:10000) 7ff935290000(10000:10000) 7ff9351f0000(70000:70000) 7ff9351d0000(3000:1000) Size: 0xbf000 (782336) bytes total, 0x2000 (8192) bytes wasted. 7 HighFrequencyHeap: 7ff9354c0000(10000:2000) 7ff935490000(10000:10000) 7ff935470000(10000:10000) 7ff935430000(10000:10000) 7ff935410000(10000:10000) 7ff9353e0000(10000:10000) 7ff9353b0000(10000:10000) 7ff935310000(10000:10000) 7ff9352e0000(10000:10000) 7ff9352c0000(10000:10000) 7ff9352a0000(10000:10000) 7ff935260000(10000:10000) 7ff9351d4000(9000:6000) Size: 0xb8000 (753664) bytes total, 0x3000 (12288) bytes wasted. 8 FixupPrecodeHeap: 7ff9354b0000(10000:10000) 7ff9354a0000(10000:10000) 7ff935480000(10000:10000) 7ff935440000(10000:10000) 7ff935420000(10000:10000) 7ff935400000(10000:10000) 7ff9353d0000(10000:10000) 7ff935320000(10000:10000) 7ff935300000(10000:10000) 7ff9352d0000(10000:10000) 7ff9352b0000(10000:10000) 7ff935270000(10000:10000) Size: 0xc0000 (786432) bytes total. 9 NewStubPrecodeHeap: 7ff935280000(10000:10000) Size: 0x10000 (65536) bytes total. 10 IndirectionCellHeap: 7ff9351e0000(6000:1000) Size: 0x1000 (4096) bytes total. 11 Total size: Size: 0x248000 (2392064) bytes total, 0x5000 (20480) bytes wasted.(内存使用不大,没异常) 12 ---------------------------------------- 13 Domain 1: 029001582830 14 LoaderAllocator: 029001582830 15 No unique loader heaps found. 16 ---------------------------------------- 17 JIT Manager: 029001585bf0 18 LoaderCodeHeap: 7ff935330000(80000:4000) Size: 0x4000 (16384) bytes total. 19 Total size: Size: 0x4000 (16384) bytes total. 20 ----------------------------------------
我们再使用【!eeheap -gc】命令查看一下 GC 堆有没有异常情况。
1 0:001> !eeheap -gc 2 3 ======================================== 4 Number of GC Heaps: 1 5 ---------------------------------------- 6 Small object heap 7 segment begin allocated committed allocated size committed size 8 generation 0: 9 02d016fdf1c0 029005000028 029005000028 029005021000 0x21000 (135168) 10 generation 1: 11 02d016fdf320 029005800028 0290058141e8 029005821000 0x141c0 (82368) 0x21000 (135168) 12 generation 2: 13 02d016fdf950 029007c00028 029007c00028 029007c01000 0x1000 (4096) 14 NonGC heap 15 segment begin allocated committed allocated size committed size 16 029001636e20 02d097be0008 02d097be1be8 02d097bf0000 0x1be0 (7136) 0x10000 (65536) 17 Large object heap 18 segment begin allocated committed allocated size committed size 19 02d016fdf3d0 029005c00028 029005c00028 029005c01000 0x1000 (4096) 20 Pinned object heap 21 segment begin allocated committed allocated size committed size 22 02d016fdec40 029003000028 029003004018 029003011000 0x3ff0 (16368) 0x11000 (69632) 23 ------------------------------ 24 GC Allocated Heap Size: Size: 0x19d90 (105872) bytes.(GC 堆才 105 KB,也没问题) 25 GC Committed Heap Size: Size: 0x65000 (413696) bytes.
GC 堆也没出现内存暴涨的情况,没什么问题。
由于大部分内存消耗并不在托管堆上,因此,我们需要使用【!address -summary】来了解进程中内存使用的情况。
1 0:001> !address -summary 2 3 --- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal 4 Free 65 7dbe`41feb000 ( 125.743 TB) 98.24% 5 MappedFile 147 200`0351a000 ( 2.000 TB) 88.62% 1.56% 6 <unknown> 82 41`97316000 ( 262.362 GB) 11.35% 0.20% 7 Heap 44 0`1fa49000 ( 506.285 MB) 0.02% 0.00%(这个是比较类似的) 8 Image 240 0`03422000 ( 52.133 MB) 0.00% 0.00% 9 Stack 15 0`00780000 ( 7.500 MB) 0.00% 0.00% 10 Other 8 0`001dd000 ( 1.863 MB) 0.00% 0.00% 11 TEB 5 0`0000c000 ( 48.000 kB) 0.00% 0.00% 12 PEB 1 0`00001000 ( 4.000 kB) 0.00% 0.00% 13 14 --- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal 15 MEM_MAPPED 154 200`03705000 ( 2.000 TB) 88.62% 1.56% 16 MEM_PRIVATE 148 41`b74de000 ( 262.864 GB) 11.37% 0.20% 17 MEM_IMAGE 240 0`03422000 ( 52.133 MB) 0.00% 0.00% 18 19 --- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal 20 MEM_FREE 65 7dbe`41feb000 ( 125.743 TB) 98.24% 21 MEM_RESERVE 100 241`95ef7000 ( 2.256 TB) 99.97% 1.76% 22 MEM_COMMIT 442 0`2810e000 ( 641.055 MB) 0.03% 0.00% 23 24 --- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal 25 PAGE_READWRITE 172 0`1ee4e000 ( 494.305 MB) 0.02% 0.00% 26 PAGE_NOACCESS 18 0`03fe6000 ( 63.898 MB) 0.00% 0.00% 27 PAGE_READONLY 151 0`02b4b000 ( 43.293 MB) 0.00% 0.00% 28 PAGE_EXECUTE_READ 63 0`026ea000 ( 38.914 MB) 0.00% 0.00% 29 PAGE_WRITECOPY 30 0`0007f000 ( 508.000 kB) 0.00% 0.00% 30 PAGE_READWRITE | PAGE_GUARD 6 0`00014000 ( 80.000 kB) 0.00% 0.00% 31 PAGE_EXECUTE_WRITECOPY 1 0`00010000 ( 64.000 kB) 0.00% 0.00% 32 PAGE_EXECUTE_READWRITE 1 0`00002000 ( 8.000 kB) 0.00% 0.00% 33 34 --- Largest Region by Usage ----------- Base Address -------- Region Size ---------- 35 Free 2d0`b9220000 7b23`496c0000 ( 123.138 TB) 36 MappedFile 7dff`44b1f000 1f5`9fa0f000 ( 1.959 TB) 37 <unknown> 290`07c01000 3f`fb3af000 ( 255.925 GB) 38 Heap 2d0`9a7f0000 0`00fcf000 ( 15.809 MB) 39 Image 7ff9`93be1000 0`00bfe000 ( 11.992 MB) 40 Stack f6`14000000 0`0017b000 ( 1.480 MB) 41 Other 290`01910000 0`00181000 ( 1.504 MB) 42 TEB f6`139fb000 0`00004000 ( 16.000 kB) 43 PEB f6`139e0000 0`00001000 ( 4.000 kB)
既然是在非托管堆上分配的,我们很容易就会联想到和 P/Invoke 有关联。此时,我们在看看源码,问题也就可以找到了。