سؤال

لدي برنامج اختبار صغير. عندما أنظر إلى كائن المكدس للخيط الرئيسي ، فإن عرضه MyClass مرتين هناك. أي أفكار لماذا يوجد اثنين من الأشياء MyClass على المكدس؟

class Program  
{  
    struct MyStruct  
    {  
        int x;  
        int y;  
    }  

    class MyClass 
    {  
        int x;  
        int y;  
    }  


    static void Main(string[] args)  
    {  
        MyStruct s ;  
        MyClass c = new MyClass();  
    }  
}  
0:000> !DumpStackObjects  
OS Thread Id: 0xf74 (0)  
RSP/REG          Object           Name  
000000000023e9e8 00000000028f3c90 ConsoleApplication2.Program+MyClass  
000000000023e9f8 00000000028f3c90 ConsoleApplication2.Program+MyClass  
000000000023ea10 00000000028f3c70 System.Object[]    (System.String[])  
000000000023eb98 00000000028f3c70 System.Object[]    (System.String[])  
000000000023ed80 00000000028f3c70 System.Object[]    (System.String[])  
000000000023eda8 00000000028f3c70 System.Object[]    (System.String[])  
هل كانت مفيدة؟

المحلول

في الواقع يظهر أن المثال واحد والوحيد يتم الرجوع إليه مرتين. لاحظ القيم في أقصى اليسار تختلف. يمكن أن تكون سجلات مختلفة أو أجزاء مختلفة من إطار المكدس والتي تشير إلى نفس الحالة.

في تجربتي يحدث هذا في كثير من الأحيان (خاصة مع بنيات التصحيح). !dso مفيد لتحديد موقع الكائنات وفي هذه الحالة العمود المهم هو عمود الكائن ، الذي يحمل المراجع الفعلية.

على سبيل المثال ، إذا قمت بتشغيل مثالك أعلاه من مصحح الأخطاء ووضع نقطة استراحة على الإخراج الرئيسي من dso يبدو أن هذا قبل عودة الطريقة الرئيسية مباشرة.

0:000> !dso
OS Thread Id: 0x1944 (0)
ESP/REG  Object   Name
eax      0240b2e0 TestApp.Program+MyClass
ecx      0240b2e0 TestApp.Program+MyClass
0014F224 0240b2d0 System.Object[]    (System.String[])
0014F3CC 0240b2d0 System.Object[]    (System.String[])
0014F400 0240b2d0 System.Object[]    (System.String[])

كما ترون كلاهما eax و ال ecx تحمل السجلات إشارة إلى المثيل على الرغم من حقيقة أن مصدر C# لديه فقط مرجع واحد.

إذا نظرت إلى رمز JIT المترجم لـ MAIN ، يبدو الأمر هكذا

0:000> !u 00200070 
Normal JIT generated code
TestApp.Program.Main(System.String[])
Begin 00200070, size 46

C:\dev2010\TestApp\TestApp\Program.cs @ 33:
>>> 00200070 55              push    ebp
00200071 8bec            mov     ebp,esp
00200073 83ec14          sub     esp,14h
00200076 33c0            xor     eax,eax
00200078 8945f4          mov     dword ptr [ebp-0Ch],eax
0020007b 8945f8          mov     dword ptr [ebp-8],eax
0020007e 894dfc          mov     dword ptr [ebp-4],ecx
00200081 833d3c31150000  cmp     dword ptr ds:[15313Ch],0
00200088 7405            je      0020008f
0020008a e8c05ac268      call    clr!JIT_DbgIsJustMyCode (68e25b4f)
0020008f 33d2            xor     edx,edx
00200091 8955f0          mov     dword ptr [ebp-10h],edx
00200094 90              nop

C:\dev2010\TestApp\TestApp\Program.cs @ 35:
00200095 b960391500      mov     ecx,153960h (MT: TestApp.Program+MyClass)
0020009a e8811ff4ff      call    00142020 (JitHelp: CORINFO_HELP_NEWSFAST)
0020009f 8945ec          mov     dword ptr [ebp-14h],eax
002000a2 8b4dec          mov     ecx,dword ptr [ebp-14h]
002000a5 ff158c391500    call    dword ptr ds:[15398Ch]     (TestApp.Program+MyClass..ctor(), mdToken: 06000003)
002000ab 8b45ec          mov     eax,dword ptr [ebp-14h]
002000ae 8945f0          mov     dword ptr [ebp-10h],eax

C:\dev2010\TestApp\TestApp\Program.cs @ 36:
002000b1 90              nop
002000b2 8be5            mov     esp,ebp
002000b4 5d              pop     ebp
002000b5 c3              ret

لاحظ التعليمات call 00142020. هذا يخلق مثيل MyClass ويعيد المرجع في eax تسجيل. بعد أن يتم تخزين المرجع في dword ptr [ebp-14h].

تقرأ التعليمات التالية القيمة المخزنة في dword ptr [ebp-14h] ويخزن القيمة في ecx السجل ، الذي يتم استخدامه بعد ذلك كمدخل للمكالمة إلى المُنشئ call dword ptr ds:[15398Ch] (TestApp.Program+MyClass..ctor(), mdToken: 06000003).

هذا ما يفسر السبب dso يسرد المرجع مرتين في هذه الحالة. ومع ذلك ، نادراً ما تحتاج إلى الدخول في التفاصيل حول هذا الأمر عند تصحيح الأخطاء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top