كيف يمكنني الحصول على حجم كتلة الذاكرة المخصصة باستخدام malloc()؟[ينسخ]

StackOverflow https://stackoverflow.com/questions/1208644

سؤال

التكرارات المحتملة:
كيف يمكنني الحصول على حجم المصفوفة من مؤشر في لغة C؟
هل هناك أي طريقة لتحديد حجم مصفوفة C++ برمجياً؟وإذا لم يكن كذلك، لماذا؟

أحصل على مؤشر إلى جزء من الذاكرة المخصصة من وظيفة نمط C.الآن ، سيكون من المثير للاهتمام حقًا أن تعرف أغراض تصحيح الأخطاء حجم كتلة الذاكرة المخصصة التي نقاطها.

هل هناك أي شيء أكثر أناقة من إثارة الاستثناء عن طريق تجاوز حدوده بشكل أعمى؟

شكرا مقدما ، أندرياس

يحرر:

أستخدم VC++2005 على نظام التشغيل Windows، وGC 4.3 على نظام Linux

تحرير 2:

أملك _msize تحت VC ++ 2005 للأسف يؤدي إلى استثناء في وضع التصحيح ....

تحرير 3:

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

إنها ليست أنيقة ولا يمكن استخدامها بأي حال من الأحوال في كود الإنتاج.

هل كانت مفيدة؟

المحلول

إنه ليس قياسيًا ولكن إذا كانت مكتبتك تحتوي على ملف msize() الوظيفة التي سوف تعطيك الحجم.

الحل الشائع هو الالتفاف malloc من خلال وظيفتك الخاصة التي تسجل كل طلب بالإضافة إلى الحجم ونطاق الذاكرة الناتج، في إصدار الإصدار، يمكنك التبديل مرة أخرى إلى الإصدار "الحقيقي" malloc.

نصائح أخرى

إذا كنت لا تمانع في استخدام العنف المهلهل من أجل تصحيح الأخطاء، فيمكنك #تعريف وحدات الماكرو لربط المكالمات بـ malloc وتحريرها وحشو أول 4 بايتات بالحجم.

على أنغام

void *malloc_hook(size_t size) {
    size += sizeof (size_t);
    void *ptr = malloc(size);
    *(size_t *) ptr = size;
    return ((size_t *) ptr) + 1;
}

void free_hook (void *ptr) {
    ptr = (void *) (((size_t *) ptr) - 1);
    free(ptr);
}

size_t report_size(ptr) {
    return * (((size_t *) ptr) - 1);
}

ثم

#define malloc(x) malloc_hook(x)

وما إلى ذلك وهلم جرا

لا توفر مكتبة وقت التشغيل C مثل هذه الوظيفة.علاوة على ذلك، فإن الاستثناء المتعمد لن يخبرك بحجم الكتلة أيضًا.

عادةً ما تكون الطريقة التي يتم بها حل هذه المشكلة في لغة C هي الاحتفاظ بمتغير منفصل يتتبع حجم الكتلة المخصصة.وبطبيعة الحال، قد يكون هذا غير مريح في بعض الأحيان، ولكن لا توجد طريقة أخرى لمعرفة ذلك بشكل عام.

مكتبة وقت التشغيل C الخاصة بك يمكن توفير بعض وظائف تصحيح أخطاء الكومة التي يمكنها الاستعلام عن الكتل المخصصة (بعد كل شيء، free() يحتاج إلى معرفة حجم الكتلة)، ولكن أيًا من هذا النوع من الأشياء سيكون غير قابل للنقل.

مع gcc و ال GNU linker, ، يمكنك التفاف بسهولة malloc

#include <stdlib.h>
#include <stdio.h>


void* __real_malloc(size_t sz);
void* __wrap_malloc(size_t sz)
{
    void *ptr;

    ptr = __real_malloc(sz);
    fprintf(stderr, "malloc of size %d yields pointer %p\n", sz, ptr);

    /* if you wish to save the pointer and the size to a data structure, 
       then remember to add wrap code for calloc, realloc and free */

    return ptr;
}

int main()
{
    char *x;
    x = malloc(103);

    return 0;
}

وتجميع مع

gcc a.c -o a -Wall -Werror -Wl,--wrap=malloc

(بالطبع، سيعمل هذا أيضًا مع كود c++ المترجم مع g++، ومع العامل الجديد (من خلال اسمه المشوه) إذا كنت ترغب في ذلك.)

في الواقع، ستستخدم المكتبة المحملة بشكل ثابت/ديناميكي أيضًا ملف __wrap_malloc.

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

لا توجد وظيفة C قياسية للقيام بذلك.اعتمادًا على نظامك الأساسي، قد تكون هناك طريقة غير محمولة - ما هي مكتبة نظام التشغيل وC التي تستخدمها؟

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

لعبة الداما الذاكرة مثل التحقق من ذاكرة Valgrind و جوجل تي سي مالوك (جزء مدقق الكومة) تتبع هذا النوع من الأشياء.

يمكنك استخدام TCMalloc لتفريغ ملف تعريف الكومة الذي يوضح المكان الذي تم تخصيص الأشياء فيه، أو يمكنك فقط التحقق منه للتأكد من أن الكومة الخاصة بك هي نفسها عند نقطتين في تنفيذ البرنامج باستخدام ساميهيب ().

الحل الجزئي:على نظام التشغيل Windows، يمكنك استخدام كومة الصفحة للقبض على الوصول إلى الذاكرة خارج الكتلة المخصصة.

PageHeap هو مدير ذاكرة بديل موجود في Windows kernel (في أنواع NT ولكن لا ينبغي لأحد أن يستخدم أي إصدار آخر في الوقت الحاضر).فهو يأخذ كل تخصيص في العملية ويعيد كتلة الذاكرة التي تتم محاذاة نهايتها مع نهاية صفحة الذاكرة، ثم يجعل الصفحة التالية غير قابلة للوصول (لا يمكن القراءة ولا الوصول للكتابة).إذا حاول البرنامج القراءة أو الكتابة بعد نهاية الكتلة، فستحصل على انتهاك وصول يمكنك اكتشافه باستخدام مصحح الأخطاء المفضل لديك.

كيف يمكن الحصول عليها:قم بتنزيل وتثبيت الحزمة Debugging Tools for Windows من Microsoft: http://www.microsoft.com/whdc/devtools/debugging/default.mspx

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

الشيء الأخير:عند الانتهاء من تصحيح الأخطاء، لا تنس أبدًا تشغيل GFlags مرة أخرى، وتعطيل PageHeap للتطبيق.يقوم GFlags بإدخال هذا الإعداد في السجل (ضمن HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\)، لذا فهو ثابت، حتى عبر عمليات إعادة التشغيل.

انتبه أيضًا إلى أن استخدام PageHeap يمكن أن يزيد من احتياجات الذاكرة لتطبيقك بشكل كبير.

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

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

أخيرًا، يوفر MSVCRT من Microsoft كومة قابلة للتصحيح تحتوي على العديد من الأدوات المفيدة التي يمكنك استخدامها في إصدار التصحيح الخاص بك للعثور على مشكلات الذاكرة: http://msdn.microsoft.com/en-us/library/bebs9zyz.aspx

في نظام التشغيل Linux، يمكنك استخدام valgrind للعثور على العديد من الأخطاء. http://valgrind.org/

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