هل يؤدي تسرب الذاكرة عند إلغاء تحميل ملف DLL إلى حدوث تسرب في عملية المضيف؟

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

سؤال

النظر في هذه الحالة:

dll = LoadDLL()
dll->do()

...
void do() {
    char *a = malloc(1024);
}
...

UnloadDLL(dll);

في هذه المرحلة، هل سيكون الـ 1k المخصص في استدعاء malloc() متاحًا للعملية المضيفة مرة أخرى؟يتم ربط DLL بشكل ثابت بـ CRT.

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

المحلول

لا، أنت لا تسرب.

إذا قمت بخلط نماذج dll (ثابتة وديناميكية)، فقد ينتهي بك الأمر إلى حدوث خطأ في الذاكرة إذا قمت بتخصيص ذاكرة في ملف dll، أو قمت بتحريرها في ملف آخر (أو تم تحريرها في ملف exe)

وهذا يعني أن الكومة التي تم إنشاؤها بواسطة CRT المرتبط بشكل ثابت ليست هي نفس الكومة مثل CRT الخاص بـ dll مختلف.

إذا قمت بالربط مع الإصدار الديناميكي من CRT، فسيكون لديك تسرب حيث تتم مشاركة الكومة بين جميع CRTs المرتبطة ديناميكيًا.هذا يعني أنه يجب عليك دائمًا تصميم تطبيقاتك لاستخدام CRTs الديناميكية، أو التأكد من عدم إدارة الذاكرة مطلقًا عبر حدود ملف dll (على سبيل المثال، إذا قمت بتخصيص ذاكرة في ملف dll، فقم دائمًا بتوفير روتين لتحريرها في نفس ملف dll)

نصائح أخرى

  1. الذاكرة المستخدمة بواسطة العملية كما يتتبعها نظام التشغيل تنطبق على العملية بأكملها وليست خاصة بملف DLL.

  2. يتم إعطاء الذاكرة للبرنامج على شكل أجزاء بواسطة نظام التشغيل، تسمى أكوام

  3. يقوم مديرو الكومة (malloc / new etc) بتقسيم القطع وتسليمها لطلب التعليمات البرمجية.

  4. فقط عند تخصيص كومة جديدة، يكتشف نظام التشغيل زيادة في الذاكرة.

  5. عندما يتم ربط DLL بشكل ثابت بمكتبة وقت تشغيل C (CRT)، يتم تجميع نسخة خاصة من CRT مع وظائف CRT التي يستدعيها رمز DLL ووضعها في الملف الثنائي لـ DLL.يتم تضمين Malloc أيضًا في هذا.

  6. سيتم استدعاء هذه النسخة الخاصة من malloc عندما يحاول الكود الموجود داخل مكتبة الارتباط الحيوي (DLL) المرتبطة بشكل ثابت تخصيص الذاكرة.

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

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

  9. ومع ذلك، إذا كان DLL مرتبطًا ديناميكيًا، فسيتم تخصيص الذاكرة بواسطة إصدار واحد مشترك من malloc، عالمي لكل التعليمات البرمجية المرتبطة في الوضع المشترك.

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

تحرير - تمت إضافة أوصاف لسيناريو الربط.

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

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

من ام اس دي ان الأخطاء المحتملة في تمرير كائنات CRT عبر حدود DLL

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

أيضًا ، نظرًا لأن كل نسخة من مكتبة CRT لديها مدير كومة خاص بها ، فإن تخصيص الذاكرة في مكتبة CRT واحدة وتمرير المؤشر عبر حدود DLL ليتم تحريرها بواسطة نسخة مختلفة من مكتبة CRT هي سبب محتمل لفساد الكومة.

أتمنى أن يساعدك هذا.

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

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

يمكن للمرء إجراء اختبار ومعرفة ما إذا كان هناك تسرب للذاكرة.يمكنك إجراء اختبار بسيط 30 مرة مع تخصيص 1 ميجابايت في كل مرة.يجب عليك معرفة ذلك بسرعة كبيرة.

شيء واحد مؤكد.إذا قمت بتخصيص ذاكرة في ملف DLL، فيجب عليك أيضًا تحرير تلك الذاكرة هناك (في ملف DLL).

على سبيل المثال، يجب أن يكون لديك شيء مثل هذا (رمز زائف بسيط ولكنه بديهي):

dll = DllLoad();

ptr = dll->alloc();

dll->free(ptr);

DllUnload(dll);

يجب أن يتم ذلك لأن ملف DLL يحتوي على كومة مختلفة عن العملية الأصلية (التي تقوم بتحميل ملف dll).

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