تتبع المكدس

في مجال الحوسبة ، يُعدّ تتبع المكدس (ويُسمى أيضًا تتبع المكدس العكسي [ 1 ] أو تتبع المكدس الخلفي [ 2 ] ) تقريرًا عن إطارات المكدس النشطة في لحظة معينة أثناء تنفيذ البرنامج . عند تشغيل برنامج، غالبًا ما يتم تخصيص الذاكرة ديناميكيًا في مكانين: المكدس والكومة . يتم تخصيص الذاكرة باستمرار على المكدس، ولكن ليس على الكومة. يشير مصطلح "المكدس" أيضًا إلى بنية برمجية، ولذلك ، ولتمييزه، يُشار إلى هذا المكدس باسم " مكدس استدعاء الدوال" الخاص بالبرنامج . من الناحية التقنية، بمجرد تخصيص كتلة من الذاكرة على المكدس، لا يمكن إزالتها بسهولة، حيث قد توجد كتل ذاكرة أخرى تم تخصيصها بعده. في كل مرة يتم فيها استدعاء دالة في البرنامج، يتم تخصيص كتلة من الذاكرة تُسمى " سجل التنشيط" أعلى مكدس الاستدعاء. بشكل عام، يخزن سجل التنشيط وسائط الدالة ومتغيراتها المحلية. يتم تحديد محتوياته وكيفية تنظيمه بواسطة اصطلاح الاستدعاء .

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

يُتيح تتبع المكدس تتبع تسلسل استدعاء الدوال المتداخلة حتى النقطة التي يتم عندها إنشاء تتبع المكدس. في سيناريو ما بعد الوفاة، يمتد هذا التتبع حتى الدالة التي حدث فيها الخطأ (ولكن ليس بالضرورة أن تكون هي السبب). لا تظهر استدعاءات الدوال الشقيقة في تتبع المكدس.

الدعم اللغوي

تدعم العديد من لغات البرمجة، بما في ذلك Java [ 3 ] و C# [ 4 ] ، استرجاع تتبع المكدس الحالي عبر استدعاءات النظام. قبل std::stacktraceإضافة الاستثناءات إلى المكتبة القياسية كحاوية لها std::stacktrace_entry، لم يكن الإصدار C++23 يدعم ذلك بشكل مدمج، ولكن يمكن لمستخدمي C++ استرجاع تتبعات المكدس باستخدام مكتبة stacktrace (على سبيل المثال) . في JavaScript ، تحتوي الاستثناءات على خاصية تتضمن تتبع المكدس من المكان الذي تم طرح الاستثناء فيه.stack

بايثون

على سبيل المثال، يحتوي برنامج بايثون التالي على خطأ.

def a () -> int :i : int = 0j : int = b ( i )أعد jdef b ( z : int ) -> int :k : int = 5إذا كانت قيمة z تساوي 0 :ج ()أعد k + zdef c () -> None :خطأ ()إذا كان __name__ يساوي "__main__" :أ ()

يؤدي تشغيل البرنامج باستخدام مترجم بايثون القياسي إلى ظهور رسالة الخطأ التالية.

تتبع الأخطاء (آخر استدعاء): الملف "file.py" ، السطر 16 ، في <module> a () الملف "file.py" ، السطر 3 ، في a j = b ( i ) الملف "file.py" ، السطر 9 ، في b c () الملف "file.py" ، السطر 13 ، في c error () خطأ في الاسم : الاسم 'error' غير مُعرَّف

يُظهر تتبع المكدس مكان حدوث الخطأ، وتحديدًا في cالدالة. كما يُظهر أن cالدالة قد تم استدعاؤها بواسطة الدالة b، والتي تم استدعاؤها بدورها بواسطة الدالة a، والتي تم استدعاؤها بدورها بواسطة الكود الموجود في السطر 16 (السطر الأخير) من البرنامج. يتم ترتيب سجلات التنشيط لكل من هذه الدوال الثلاث في مكدس بحيث aتشغل الدالة أسفل المكدس وتشغل الدالة cأعلى المكدس.

جافا

في لغة جافا ، يمكن تفريغ آثار المكدس يدويًا باستخدام java.lang.Thread::dumpStack()[ 5 ]. خذ المدخلات التالية:

public class Main {static void demo () {demo1 ();}static void demo1 () {demo2 ();}static void demo2 () {demo3 ();}static void demo3 () {Thread.dumpStack ( ) ;}public static void main ( String args [] ) {عرض توضيحي ();}}

يسرد الاستثناء الدوال بترتيب تنازلي، لذا فإن الاستدعاء الأكثر داخلية هو الأول.

java.lang.Exception : تتبع المكدس في java.lang.Thread.dumpStack ( Thread.java:1336 ) في Main.demo3 ( Main.java:15 ) في Main.demo2 ( Main.java:11 ) في Main.demo1 ( Main.java:7 ) في Main.demo ( Main.java:3 ) في Main.main ( Main.java:19 )

تتيح لغة جافا أيضًا استرجاع تتبع المكدس الحالي باستخدام java.lang.Thread::getStackTrace()، أو عرض تتبع المكدس عند حدوث خطأ باستخدام java.lang.Throwable::printStackTrace(). يُمثل تتبع المكدس في جافا java.lang.StackTraceElement[]كمصفوفة. [ 6 ]

لغة C ولغة C++

لا تدعم لغة C بشكل أصلي الحصول على تتبعات المكدس، ولكن مكتبات مثل glibc توفر هذه الوظيفة. [ 7 ]

في لغتي C و C++، قد تتداخل بعض تحسينات المُصرّف مع معلومات مكدس الاستدعاءات التي يمكن استعادتها أثناء التشغيل. على سبيل المثال، قد يؤدي التضمين المباشر إلى فقدان إطارات المكدس، وقد تستبدل تحسينات استدعاء الذيل إطار مكدس بآخر، وقد يمنع حذف مؤشر الإطار أدوات تحليل مكدس الاستدعاءات من تفسير محتويات مكدس الاستدعاءات بشكل صحيح. [ 7 ]

على سبيل المثال، تقوم دالة glibc backtrace()بإرجاع مخرجات تحتوي على دالة البرنامج وعنوان الذاكرة.

. / a . out () [ 0x40067f ] . / a . out () [ 0x4006fe ] . / a . out () [ 0x40070a ] / lib / x86_64 - linux - gnu / libc . so .6 ( __libc_start_main + 0xf5 ) [ 0x7f7e60738f45 ] . / a . out () [ 0x400599 ]

قبل إصدار C++23 ، لم تكن هناك آليات في لغة C++ للحصول على تتبعات المكدس، ولكن مكتبات خارجية مثل Boost.Stacktrace كانت توفر هذه الميزة. [ 8 ] أضافت C++23 تتبعات المكدس باستخدام std::stacktrace[ std::stacktrace_entry9 ] ويمكن استخراج تتبعات المكدس يدويًا عن طريق طباعة القيمة المُعادة من دالة عضو ثابتة std::stacktrace::current(). [ 10 ]

استيراد std ؛باستخدام std :: stacktrace ;void bar () { std :: println ( "Stacktrace from bar(): \n {}" , stacktrace :: current ()); }void foo () { bar (); }int main () { foo (); }

سي شارب

توفر لغة C#System.Diagnostics.StackTrace فئة. [ 11 ]

الصدأ

يحتوي Rust على نوعين من الأخطاء. الدوال التي تستخدم ماكرو panic تكون "غير قابلة للاسترداد"، وسيؤدي ذلك إلى تعطل الخيط الحالي نتيجةً لعملية فكّ التتبع. أما الدوال التي تُرجع قيمةً std::result::Resultفهي "قابلة للاسترداد" ويمكن التعامل معها بسلاسة. [ 12 ] مع ذلك، لا يمكن للأخطاء القابلة للاسترداد أن تُولّد تتبعًا للمكدس لأنها تُضاف يدويًا وليست نتيجةً لخطأ وقت التشغيل.

اعتبارًا من يونيو 2021، توفر لغة Rust دعمًا تجريبيًا لتتبع الأخطاء غير القابلة للاسترداد. تدعم Rust الطباعة إلى الخطأ القياسي (stderr) عند حدوث حالة ذعر في أحد الخيوط، ولكن يجب تفعيل هذه الميزة عن طريق ضبط RUST_BACKTRACEمتغير البيئة . [ 13 ]

عند تفعيل هذه الميزة، تبدو عمليات التتبع هذه مشابهة لما يلي، مع ظهور أحدث استدعاء أولاً.

حدث خطأ في الخيط ' main ' عند ' execute_to_panic ' ، في الملف main.rs ، السطر 3. تتبع المكدس : 0 : std :: sys :: imp :: backtrace :: tracing :: imp :: unwind_backtrace 1 : std :: panicking :: default_hook :: {{ closure }} 2 : std :: panicking :: default_hook 3 : std :: panicking :: rust_panic_with_hook 4 : std :: panicking :: begin_panic 5 : futures :: task_impl :: with 6 : futures :: task_impl :: park ...

انظر أيضاً

مراجع

  1. "دليل مكتبة libc: تتبعات الأخطاء" . gnu.org . تم الاطلاع عليه بتاريخ 8 يوليو 2014 .
  2. "traceback — طباعة أو استرجاع تتبع المكدس" . python.org . تم الاسترجاع في 8 يوليو 2014 .
  3. "Thread (Java SE 16 & JDK 16)" . مواصفات واجهة برمجة تطبيقات Java Platform Standard Edition وJava Development Kit الإصدار 16. 2021-03-04 . تم الاطلاع عليه بتاريخ 2021-07-04 .
  4. "خاصية تتبع مكدس البيئة (النظام)" . وثائق مايكروسوفت . 2021-05-07 . تم الاطلاع عليه بتاريخ 2021-07-04 .
  5. "Thread (Java Platform SE 8)" . docs.oracle.com . تم الاطلاع عليه بتاريخ 15-06-2021 .
  6. شركة أوراكل. "فئة StackTraceElement" . docs.oracle.com . شركة أوراكل . تم الاطلاع عليه في 1 مايو 2026 .
  7. 1 2 "تتبعات الأخطاء (مكتبة GNU C)" . www.gnu.org . تم الاطلاع عليه بتاريخ 15-06-2021 .
  8. "دليل البدء - 1.76.0" . www.boost.org . تاريخ الاسترجاع: 15 يونيو 2021 .
  9. cppreference.com. "Standard library header <stacktrace> (C++23)" . cppreference.com . cppreference.com . تم الاطلاع عليه في 1 مايو 2026 .
  10. "مسودة عمل، معيار للغة البرمجة C++" (ملف PDF) . open-std.org . ISO/IEC. 2021-10-23. ص 766. 
  11. مايكروسوفت ليرن. "فئة تتبع المكدس" . مايكروسوفت ليرن . مايكروسوفت ليرن . تم الاسترجاع في 1 مايو 2026 .
  12. "rustonomicon unwinding - Rust" . doc.rust-lang.org .
  13. "std::backtrace - Rust" . doc.rust-lang.org . تم الاطلاع عليه بتاريخ 15-06-2021 .