mallopt(3)

الاسم
mallopt - ضبط معاملات تخصيص الذاكرة

المكتبة
مكتبة سي المعيارية (libc، -lc)

موجز
#include <malloc.h>

int mallopt(int param, int value);

الوصف
تُعدّل دالة mallopt() المعاملات التي تتحكم في سلوك دوال تخصيص الذاكرة (انظر malloc(3)). تُحدد الوسيطة param المعامل المراد تعديله، وتُحدد value القيمة الجديدة لذلك المعامل.

يمكن تحديد القيم التالية لـ param:

M_ARENA_MAX
    إذا كان لهذا المعامل قيمة غير صفرية، فإنه يُحدد حدًا صارمًا على العدد الأقصى من الساحات التي يمكن إنشاؤها. تمثل الساحة مجموعة من الذاكرة يمكن استخدامها بواسطة استدعاءات malloc(3) (وما شابهها) لخدمة طلبات التخصيص. الساحات آمنة للخيوط، وبالتالي قد تحتوي على طلبات ذاكرة متزامنة متعددة. المفاضلة هي بين عدد الخيوط وعدد الساحات. كلما زاد عدد الساحات، انخفض التنافس لكل خيط، ولكن زاد استخدام الذاكرة.

    القيمة المبدئية لهذا المعامل هي 0، مما يعني أن الحد على عدد الساحات يُحدد وفقًا لإعداد M_ARENA_TEST.

    هذا المعامل متاح منذ glibc 2.10 عبر --enable-experimental-malloc، ومنذ glibc 2.15 بشكل مبدئي. في بعض إصدارات المخصص، لم يكن هناك حد على عدد الساحات المنشأة (مثل CentOS 5, RHEL 5).

    عند استخدام إصدارات أحدث من glibc، قد تُظهر التطبيقات في بعض الحالات تنافسًا عاليًا عند الوصول إلى الساحات. في هذه الحالات، قد يكون من المفيد زيادة M_ARENA_MAX لمطابقة عدد الخيوط. هذا مشابه في السلوك للاستراتيجيات التي تتبعها tcmalloc و jemalloc (مثل تجمعات التخصيص لكل خيط).

M_ARENA_TEST
    يُحدد هذا المعامل قيمة، بعدد الساحات المنشأة، عندها سيتم فحص تكوين النظام لتحديد حد صارم على عدد الساحات المنشأة. (انظر M_ARENA_MAX لتعريف الساحة.)

    حساب الحد الصارم للساحة هو محدد بالتطبيق وعادةً يُحسب كمضاعف لعدد وحدات المعالجة المركزية المتاحة. بمجرد حساب الحد الصارم، تكون النتيجة نهائية وتُقيد العدد الإجمالي للساحات.

    القيمة المبدئية لمعامل M_ARENA_TEST هي 2 على الأنظمة حيث sizeof(long) هو 4؛ وإلا فإن القيمة المبدئية هي 8.

    هذا المعامل متاح منذ glibc 2.10 عبر --enable-experimental-malloc، ومنذ glibc 2.15 بشكل مبدئي.

    قيمة M_ARENA_TEST لا تُستخدم عندما يكون لـ M_ARENA_MAX قيمة غير صفرية.

M_CHECK_ACTION
    يُتحكم في إعداد هذا المعامل في كيفية استجابة glibc عند اكتشاف أنواع مختلفة من أخطاء البرمجة (مثل تحرير نفس المؤشر مرتين). تُحدد البتات الثلاث الأقل أهمية (2 و 1 و 0) من القيمة المخصصة لهذا المعامل سلوك glibc، كما يلي:

    البت 0
        إذا تم تعيين هذه البتة، فاطبع رسالة من سطر واحد على stderr تُقدم تفاصيل عن الخطأ. تبدأ الرسالة بالسلسلة "*** glibc detected ***"، متبوعة باسم البرنامج، واسم دالة تخصيص الذاكرة التي اكتُشف فيها الخطأ، ووصفًا موجزًا للخطأ، وعنوان الذاكرة حيث اكتُشف الخطأ.

    البت 1
        إذا وُضعت هذه البتة، فبعد طباعة أي رسالة خطأ محددة بالبتة 0، يُنهى البرنامج باستدعاء abort(3). منذ glibc 2.4، إذا وُضعت البتة 0 أيضًا، فبين طباعة رسالة الخطأ والإنهاء، يطبع البرنامج أيضًا أثر استدعاءات على نمط backtrace(3)، ويطبع تخطيط ذاكرة العملية بأسلوب /proc/pid/maps (انظر proc(5)).

    البتة 2 (منذ glibc 2.4)
        لهذه البتة تأثير فقط إذا وُضعت البتة 0 أيضًا. إذا وُضعت هذه البتة، فتُبسّط رسالة السطر الواحد التي تصف الخطأ لتحتوي فقط على اسم الدالة التي اكتُشف فيها الخطأ ووصفًا موجزًا للخطأ.

    تُتجاهل البتات المتبقية في القيمة.

    بدمج التفاصيل أعلاه، تكون القيم الرقمية التالية ذات معنى لـ M_CHECK_ACTION:

    0   تجاهل حالات الخطأ؛ متابعة التنفيذ (مع نتائج غير محددة).

    1   طباعة رسالة خطأ مفصلة ومتابعة التنفيذ.

    2   إنهاء البرنامج.

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

    5   طباعة رسالة خطأ بسيطة ومتابعة التنفيذ.

    7   طباعة رسالة خطأ بسيطة، وأثر استدعاءات، وتخطيطات الذاكرة، وإنهاء البرنامج.

    منذ glibc 2.3.4، القيمة المبدئية للمعامل M_CHECK_ACTION هي 3. في glibc 2.3.3 وما قبله، القيمة المبدئية هي 1.

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

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

    القيمة المبدئية هي 65,536، وهي قيمة ليس لها أهمية خاصة وتخدم فقط كإجراء وقائي. يؤدي تعيين هذا المعامل إلى 0 إلى تعطيل استخدام mmap(2) لخدمة طلبات التخصيص الكبيرة.

M_MMAP_THRESHOLD
    بالنسبة للتخصيصات الأكبر من أو المساوية للحد المحدد (بالبايت) بواسطة M_MMAP_THRESHOLD التي لا يمكن تلبيتها من القائمة الحرة، تستخدم دوال تخصيص الذاكرة mmap(2) بدلاً من زيادة فاصل البرنامج باستخدام sbrk(2).

    تخصيص الذاكرة باستخدام mmap(2) له ميزة كبيرة وهي أن كتل الذاكرة المخصصة يمكن دائمًا إطلاقها بشكل مستقل إلى النظام. (على النقيض، لا يمكن تقليم الكومة إلا إذا تم تحرير الذاكرة في الطرف العلوي.) من ناحية أخرى، هناك بعض العيوب لاستخدام mmap(2): لا توضع المساحة غير المخصصة في القائمة الحرة لإعادة استخدامها في التخصيصات اللاحقة؛ قد تُهدر الذاكرة لأن تخصيصات mmap(2) يجب أن تكون محاذية للصفحات؛ ويجب على النواة أداء المهمة المكلفة لتصفير الذاكرة المخصصة عبر mmap(2). تؤدي موازنة هذه العوامل إلى إعداد مبدئي قدره 128*1024 للمعامل M_MMAP_THRESHOLD.

    الحد الأدنى لهذا المعامل هو 0. الحد الأعلى هو DEFAULT_MMAP_THRESHOLD_MAX: 512*1024 على أنظمة 32 بت أو 4*1024*1024*sizeof(long) على أنظمة 64 بت.

    ملاحظة: في الوقت الحالي، يستخدم glibc حد mmap ديناميكي مبدئيًا. القيمة المبدئية للحد هي 128*1024، ولكن عندما تُحرر كتل أكبر من الحد الحالي وأقل من أو تساوي DEFAULT_MMAP_THRESHOLD_MAX، يُضبط الحد لأعلى ليتوافق مع حجم الكتلة المحررة. عندما يكون تحديد حد mmap الديناميكي ساريًا، يُضبط حد تقليم الكومة ديناميكيًا أيضًا ليكون ضعف حد mmap الديناميكي. يُعطل الضبط الديناميكي لحد mmap إذا وُضع أي من المعاملات M_TRIM_THRESHOLD أو M_TOP_PAD أو M_MMAP_THRESHOLD أو M_MMAP_MAX.

M_MXFAST (منذ glibc 2.3)
    يُعيِّن الحد الأعلى لطلبات تخصيص الذاكرة التي تُلبى باستخدام "الصناديق السريعة". (وحدة قياس هذا المعامل هي البايت.) الصناديق السريعة هي مناطق تخزين تحتوي على كتل ذاكرة مُحررة من نفس الحجم دون دمج الكتل الحرة المجاورة. يمكن معالجة إعادة تخصيص كتل من نفس الحجم لاحقًا بسرعة كبيرة عن طريق التخصيص من الصندوق السريع، على الرغم من أن تجزئة الذاكرة والبصمة الكلية للذاكرة للبرنامج قد تزداد.

    القيمة المبدئية لهذا المعامل هي 64*sizeof(size_t)/4 (أي 64 على معماريات 32 بت). نطاق هذا المعامل هو من 0 إلى 80*sizeof(size_t)/4. تعطيل استخدام الصناديق السريعة يكون بضبط M_MXFAST إلى 0.

M_PERTURB (منذ glibc 2.4)
    إذا ضُبط هذا المعامل إلى قيمة غير صفرية، فإن بايتات الذاكرة المخصصة (بخلاف التخصيصات عبر calloc(3)) تُهيأ إلى مكمل القيمة في البايت الأقل أهمية من value، وعندما تُحرر الذاكرة المخصصة باستخدام free(3)، تُضبط البايتات المحررة إلى البايت الأقل أهمية من value. يمكن أن يكون هذا مفيدًا لاكتشاف الأخطاء حيث تعتمد البرامج بشكل غير صحيح على أن الذاكرة المخصصة قد هُيئت إلى الصفر، أو تعيد استخدام قيم في ذاكرة حُررت بالفعل.

    القيمة المبدئية لهذا المعامل هي 0.

M_TOP_PAD
    يُعرِّف هذا المعامل مقدار الحشو الذي يُستخدم عند استدعاء sbrk(2) لتعديل فاصل البرنامج. (وحدة قياس هذا المعامل هي البايت.) لهذا المعامل تأثير في الظروف التالية:

    •   عند زيادة فاصل البرنامج، تُضاف بايتات M_TOP_PAD إلى طلب sbrk(2).

    •   عندما تُقلم الكومة نتيجة لاستدعاء free(3) (انظر مناقشة M_TRIM_THRESHOLD)، يُحفظ هذا القدر من المساحة الحرة في أعلى الكومة.

    في كلتا الحالتين، يُقرَّب مقدار الحشو دائمًا إلى حد صفحة النظام.

    تعديل M_TOP_PAD هو مقايضة بين زيادة عدد استدعاءات النظام (عند ضبط المعامل منخفضًا) وإهدار الذاكرة غير المستخدمة في أعلى الكومة (عند ضبط المعامل مرتفعًا).

    القيمة المبدئية لهذا المعامل هي 128*1024.

M_TRIM_THRESHOLD
    عندما ينمو مقدار الذاكرة الحرة المتجاورة في أعلى الكومة بشكل كافٍ، يستخدم free(3) sbrk(2) لتحرير هذه الذاكرة إلى النظام. (يمكن أن يكون هذا مفيدًا في البرامج التي تستمر في التنفيذ لفترة طويلة بعد تحرير كمية كبيرة من الذاكرة.) يُحدد معامل M_TRIM_THRESHOLD الحد الأدنى للحجم (بالبايت) الذي يجب أن تبلغه كتلة الذاكرة هذه قبل استخدام sbrk(2) لتقليم الكومة.

    القيمة المبدئية لهذا المعامل هي 128*1024. ضبط M_TRIM_THRESHOLD إلى -1 يُعطل التقليم تمامًا.

    تعديل M_TRIM_THRESHOLD هو مقايضة بين زيادة عدد استدعاءات النظام (عند ضبط المعامل منخفضًا) وإهدار الذاكرة غير المستخدمة في أعلى الكومة (عند ضبط المعامل مرتفعًا).

  متغيرات البيئة
يمكن تعريف عدد من متغيرات البيئة لتعديل بعض المعاملات نفسها التي يتحكم بها mallopt(). استخدام هذه المتغيرات له ميزة أن شفرة مصدر البرنامج لا تحتاج إلى تغيير. لكي تكون فعالة، يجب تعريف هذه المتغيرات قبل أول استدعاء لدالة تخصيص ذاكرة. (إذا ضُبطت المعاملات نفسها عبر mallopt()، فإن إعدادات mallopt() تأخذ الأولوية.) لأسباب أمنية، تُتجاهل هذه المتغيرات في برامج set-user-ID و set-group-ID.

متغيرات البيئة هي كما يلي (لاحظ الشرطة السفلية الزائدة في نهاية اسم بعض المتغيرات):

MALLOC_ARENA_MAX
    تتحكم في نفس المعامل كدالة mallopt() M_ARENA_MAX.

MALLOC_ARENA_TEST
    تتحكم في نفس المعامل كدالة mallopt() M_ARENA_TEST.

MALLOC_CHECK_
    يتحكم متغير البيئة هذا في نفس المعامل كدالة mallopt() M_CHECK_ACTION. إذا وُضع هذا المتغير بقيمة غير صفرية، فتُستخدم تطبيق خاص لدوال تخصيص الذاكرة. (يُحقق ذلك باستخدام ميزة malloc_hook(3).) يُجري هذا التطبيق فحص أخطاء إضافيًا، لكنه أبطأ من المجموعة القياسية لدوال تخصيص الذاكرة. (لا يكتشف هذا التطبيق جميع الأخطاء المحتملة؛ قد تظل تسريبات الذاكرة تحدث.)

    يجب أن تكون القيمة المُسندة لمتغير البيئة هذا رقمًا واحدًا، ومعناه كما هو موصوف لـ M_CHECK_ACTION. تُتجاهل أي محارف تتجاوز الرقم الأول.

    لأسباب أمنية، يُعطّل تأثير MALLOC_CHECK_ مبدئيًا لبرامج set-user-ID و set-group-ID. لكن، إذا وُجد الملف /etc/suid-debug (محتوى الملف غير ذي صلة)، فإن MALLOC_CHECK_ يكون له تأثير أيضًا لبرامج set-user-ID و set-group-ID.

MALLOC_MMAP_MAX_
    تتحكم في نفس المعامل كدالة mallopt() M_MMAP_MAX.

MALLOC_MMAP_THRESHOLD_
    تتحكم في نفس المعامل كدالة mallopt() M_MMAP_THRESHOLD.

MALLOC_PERTURB_
    تتحكم في نفس المعامل كدالة mallopt() M_PERTURB.

MALLOC_TRIM_THRESHOLD_
    تتحكم في نفس المعامل كدالة mallopt() M_TRIM_THRESHOLD.

MALLOC_TOP_PAD_
    تتحكم في نفس المعامل كدالة mallopt() M_TOP_PAD.

قيمة الإرجاع
عند النجاح، تُرجع mallopt() 1. عند الخطأ، تُرجع 0.

الأخطاء
عند الخطأ، لا يُوضع errno.

الإصدارات
توجد دالة مماثلة في العديد من مشتقات System V، لكن نطاق القيم للمعامل param يختلف عبر الأنظمة. عرّف SVID الخيارات M_MXFAST وM_NLBLKS وM_GRAIN وM_KEEP، لكن أول هذه الخيارات فقط هو المُنفَّذ في glibc.

المعايير
لا شيء.

التاريخ
glibc 2.0.

العلل
تحديد قيمة غير صالحة للمعامل param لا يُولّد خطأ.

خطأ حسابي داخل تنفيذ glibc يعني أن استدعاءً بالشكل:

    mallopt(M_MXFAST, n)

لا يُؤدّي إلى استخدام fastbins لجميع التخصيصات ذات الحجم حتى n. لضمان النتائج المرغوبة، يجب تقريب n لأعلى إلى المضاعف التالي الأكبر من أو يساوي (2k+1)*sizeof(size_t)، حيث k عدد صحيح.

إذا استُخدم mallopt() لتعيين M_PERTURB، فكما هو متوقع، تُهيّأ بايتات الذاكرة المُخصّصة إلى مكمل البايت في value، وعند تحرير تلك الذاكرة، تُهيّأ بايتات المنطقة إلى البايت المُحدّد في value. لكن، يوجد خطأ بإزاحة sizeof(size_t) في التنفيذ: بدلاً من تهيئة كتلة الذاكرة المُحرَّرة بدقة بواسطة الاستدعاء free(p)، تُهيّأ الكتلة التي تبدأ عند p+sizeof(size_t).

أمثلة
يُوضّح البرنامج أدناه استخدام M_CHECK_ACTION. إذا زُوّد البرنامج بمُعامل (عدد صحيح) من سطر الأوامر، فسيُستخدم ذلك المُعامل لتعيين معامل M_CHECK_ACTION. ثم يُخصّص البرنامج كتلة ذاكرة، ويُحرّرها مرتين (خطأ).

يُظهر جلسة الصدفة التالية ما يحدث عند تشغيل هذا البرنامج تحت glibc، بالقيمة المبدئية لـ M_CHECK_ACTION:

    $ ./a.out;
    main(): returned from first free() call
    *** glibc detected *** ./a.out: double free or corruption (top): 0x09d30008 ***
    ======= Backtrace: =========
    /lib/libc.so.6(+0x6c501)[0x523501]
    /lib/libc.so.6(+0x6dd70)[0x524d70]
    /lib/libc.so.6(cfree+0x6d)[0x527e5d]
    ./a.out[0x80485db]
    /lib/libc.so.6(__libc_start_main+0xe7)[0x4cdce7]
    ./a.out[0x8048471]
    ======= Memory map: ========
    001e4000-001fe000 r-xp 00000000 08:06 1083555    /lib/libgcc_s.so.1
    001fe000-001ff000 r--p 00019000 08:06 1083555    /lib/libgcc_s.so.1
    [some lines omitted]
    b7814000-b7817000 rw-p 00000000 00:00 0
    bff53000-bff74000 rw-p 00000000 00:00 0          [stack]
    Aborted (core dumped)

تُظهر التشغيلات التالية النتائج عند استخدام قيم أخرى لـ M_CHECK_ACTION:

    $ ./a.out 1;             # تشخيص الخطأ والاستمرار
    main(): returned from first free() call
    *** glibc detected *** ./a.out: double free or corruption (top): 0x09cbe008 ***
    main(): returned from second free() call
    $ ./a.out 2;             # إجهاض بدون رسالة خطأ
    main(): returned from first free() call
    Aborted (core dumped)
    $ ./a.out 0;             # تجاهل الخطأ والاستمرار
    main(): returned from first free() call
    main(): returned from second free() call

يُظهر التشغيل التالي كيفية تعيين نفس المعامل باستخدام متغير البيئة MALLOC_CHECK_:

    $ MALLOC_CHECK_=1 ./a.out;
    main(): returned from first free() call
    *** glibc detected *** ./a.out: free(): invalid pointer: 0x092c2008 ***
    main(): returned from second free() call

  مصدر البرنامج
    #include <malloc.h>
    #include <stdio.h>
    #include <stdlib.h>

    int
    main(int argc, char *argv[])
    {
        char *p;

        if (argc > 1) {
            if (mallopt(M_CHECK_ACTION, atoi(argv[1])) != 1) {
                fprintf(stderr, "mallopt() failed");
                exit(EXIT_FAILURE);
            }
        }

        p = malloc(1000);
        if (p == NULL) {
            fprintf(stderr, "malloc() failed");
            exit(EXIT_FAILURE);
        }

        free(p);
        printf("%s(): returned from first free() call\n", __func__);

        free(p);
        printf("%s(): returned from second free() call\n", __func__);

        exit(EXIT_SUCCESS);
    }

انظر أيضًا
mmap(2), sbrk(2), mallinfo(3), malloc(3), malloc_hook(3), malloc_info(3), malloc_stats(3), malloc_trim(3), mcheck(3), mtrace(3), posix_memalign(3)

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.