> ## Content Index
> Fetch the complete content index at: https://informatic-ar.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# ما هو الـ stacktrace؟
- URL: https://informatic-ar.com/java-stacktrace/
- Published: 2014-10-06T18:03:15.000Z
- Updated: 2026-10-04T04:35:41.000Z
- Author: فؤاد المالكي
- Tags: برمجة, جافا, #wordpress-archive, #Import 2026-10-03 20:48

في لغة الجافا، تنقسم ذاكرة الـ JVM إلى عدة أقسام، ومنها ما يسمى بالـ stack. عند استدعاء دالة س (method) فإنه يُنشأ frameبداخله معلومات الدالة س ويوضع هذا الـ frame أعلى الـ stack. وعند الانتهاء من تنفيذ الدالة س، يتم إخراج الـ stack frame الخاص بالدالة س من الـ stack ويرجع مسار التنفيذ (flow of control) إلى الدالة السابقة والتي استدعت الدالة س.

```csharp
public class Main
{
    public static void main(String[] args)
    {
        x();
    }

    public static void x()
    {
        y();
    }

    public static void y()
    {
        // ...
    }
}
```

شكل الـ stack سيكون كالتالي:

[![stacks](https://informatic-ar.com/wp-content/uploads/2014/10/stacks.png)](https://informatic-ar.com/wp-content/uploads/2014/10/stacks.png)

بدايةً يقوم الـ JVM بإنشاء الـ main thread ثم يقوم باستدعاء دالة ()main ويضع frame خاص بهذه الدالة في الـ stack. خلال تنفيذ دالة الـ ()main سيقوم باستدعاء الدالة ()x وتباعاً يضع frame خاص بها في الـ stack. وخلال تنفيذ الدالة ()x يستدعي الدالة ()yويضع frame في الـ stack. عند الانتهاء من تنفيذ الدالة ()y يقوم الـ JVM بإزالة الـ frame الموجود بأعلى الـ stack وهو الـ frameالخاص بالدالة ()y. بعد ذلك يعود لاستكمال تنفيذ الدالة ()x ويزيل الـ frame الخاص بها عند الانتهاء من تنفيذها. وأخيراً يعود للدالة()main ويكمل تنفيذها، وعند الانتهاء منها يزيل آخر frame موجود في الـ stack ويقوم بإنهاء الـ main tread (ليس شرطاً أن ينتهي البرنامج بانتهاء الـ main thread).

### ما هو الـ stacktrace؟

الـ stacktrace باختصار هو سلسلة من الاستدعاءات للدوال method invocations مطابقة للـ stack frames. يستخدم الـ stacktrace عادةً في معالجة الأخطاء واكتشاف مصدرها. لنأخذ مثال بسيط لتتضح الصورة:

```csharp
import java.io.IOException;

public class Main
{
    public static void main(String[] args) throws Exception
    {
        x();
    }

    public static void x() throws Exception
    {
        y();
    }

    public static void y() throws IOException
    {
        throw new IOException("IOException in y()");
    }
}
```

يتم طباعة الـ stacktrace على الشاشة في حالتين:

\- إما أن نمسك الـ exception في try and catch وبداخل الـ catch نطبع الـ stacktrace عن طريق الدالة ()e.printStackTraceحيث أن e هو مرجع للخطأ reference for the exception.  
\- أو نقوم برمي الـ exception وتحويله (exception propagation) إلى الدالة التي استدعت الدالة الحالية، حتى يصل الـ exception إلى آخر frame في الـ stack كما فعلنا في المثال الأخير.

برنامج الجافا في المثال الأخير سيطبع الـ stacktrace التالي:

```javastacktrace
Exception in thread "main" java.io.IOException: IOException in y()
    at Main.y(Main.java:17)
    at Main.x(Main.java:12)
    at Main.main(Main.java:7)

```

وكقاعدة عامة في أي stacktrace:

\- السطر الأول يتكون من ٣‎ معلومات مهمة: اسم الـ thread، ونوع الـ exception، ورسالة الخطأ (إن وجدت). في المثال السابق اسم الـthread كان main، ونوع الـ exception كان java.io.IOException، ورسالة الخطأ كانت ()IOExcpetion in y.  
\- السطر الثاني يكون دائماً مصدر الـ exception، وفي الكود يكون المصدر هو الـ constructor الخاص بالـ exception. في المثال السابق كان مصدر الخطأ في السطر ١٧ وهو ;("()throw new IOException("IOException in y.  
\- السطر الأخير يحتوي على اسم الـ method التي تكون مدخل الـ thread وبدايته. في المثال السابق، مدخل الـ thread هو الدالة main.

### الـ stacktrace مع Caused by

أحياناً يكون خطأ ما سببه خطأ آخر، ولذلك يمكن في لغة الجافا ربط exception معين على أنه سبب لـ exception آخر عن طريق تمريره كـ parameter في الـ constructor أو عن طريق استخدام الدالة ()initCause على مرجع الـ exception الجديد. وربما الخطأ س سببه الخطأ ص، والخطأ ص سببه الخطأ ع .. وهكذا. الـ stacktrace الناتج سيحتوي على معلومات الـ exception الجديد وجميع الـexceptions المتسببة فيه مفصولة فيما بينهم بالجملة Caused by. المثال التالي سيوضح ذلك:

```csharp
import java.io.IOException;

public class Main
{
    public static void main(String[] args) throws Exception
    {
        x();
    }

    public static void x() throws Exception
    {
        try
        {
            y();
        }
        catch (IOException e)
        {
            // ex is caused by e
            Exception ex = new Exception("Exception in x()");
            ex.initCause(e);
            throw ex;

            // or
            // throw new Exception("Exception in x()", e)
        }
    }

    public static void y() throws IOException
    {
        throw new IOException("IOException in y()");
    }
}
```

والـ stacktrace الناتج يكون كالتالي:

```javastacktrace
Exception in thread "main" java.lang.Exception: Exception in x()
    at Main.x(Main.java:19)
    at Main.main(Main.java:7)
Caused by: java.io.IOException: IOException in y()
    at Main.y(Main.java:30)
    at Main.x(Main.java:14)
    ... 1 more
```

نفس القاعدة السابقة تنطبق على الـ stacktrace الحالي باستثناء أنه لا يكتب اسم الـ thread في الـ exception الموجود بعد Caused by. أيضاً يوجد اختلاف طفيف هنا وهو السطر الأخير. السطر المفقود هذا يمكنك الحصول عليه من الـ exception السابق له. المثال الآتي سيوضح كيف يمكنك الحصول على السطور المفقودة من الـ stacktrace:

لنفرض أنه لدينا الـ stacktrace التالي:

```javastacktrace
Exception in thread "main" ExceptionA
    at A5
    at A4
    at A3
    at A2
    at A1
Caused by: ExceptionB
    at B6
    at B5
    at B4
    ... 3 more
Caused by: ExceptionC
    at C8
    at C7
    at C6
    ... 5 more
```

كقاعدة عامة، إذا كان المفقود س من السطور في exception معين، نأخذ آخر س من السطور من الـ exception السابق له. وبالتالي الـstacktrace الكامل سيكون بالشكل التالي:

```javastacktrace
Exception in thread "main" ExceptionA
    at A5
    at A4
    at A3
    at A2
    at A1
Caused by: ExceptionB
    at B6
    at B5
    at B4
    at A3
    at A2
    at A1
Caused by: ExceptionC
    at C8
    at C7
    at C6
    at B5
    at B4
    at A3
    at A2
    at A1
```

### الـ stacktrace مع javac options -g & -g:none

عند عمل compile بالأمر javac -g فإن الـ stacktrace يكون محتوياً على أرقام الأسطر كما في الأمثلة السابقة، بينما لو تم عملcompile بالأمر javac -g:none فإن الـ stacktrace للمثال الأخير سيكون كالتالي:

```javastacktrace
Exception in thread "main" java.lang.Exception: Exception in x()
    at Main.x(Unknown Source)
    at Main.main(Unknown Source)
Caused by: java.io.IOException: IOException in y()
    at Main.y(Unknown Source)
    ... 2 more
```

لاحظ الاختلاف!

### الـ stacktrace بدون exception

يمكن في لغة الجافا الحصول على stacktrace من أي مكان في الكود وطباعته مباشرة، دون الحاجة إلى exception. لاحظ المثال التالي:

```csharp
public class Main
{
    public static void main(String[] args)
    {
        x();
    }

    public static void x()
    {
        y();
    }

    public static void y()
    {
        Thread currentThread = Thread.currentThread();
        StackTraceElement[] elements = currentThread.getStackTrace();
        for (StackTraceElement element: elements)
        {
            System.out.println(element);
        }
    }
}
```

والناتج سيكون كالتالي:

```javastacktrace
java.lang.Thread.getStackTrace(Unknown Source)
Main.y(Main.java:16)
Main.x(Main.java:10)
Main.main(Main.java:5)
```