تخصيص الذاكرة الديناميكية في لغة سي

يشير تخصيص الذاكرة الديناميكي في لغة C إلى إجراء إدارة يدوية للذاكرة لتخصيص الذاكرة الديناميكي في لغة البرمجة C عبر مجموعة من الوظائف في مكتبة C القياسية ، وهي malloc و realloc و calloc و align_alloc و free . [1] [2] [3]

تتضمن لغة برمجة C++ هذه الوظائف؛ ومع ذلك، توفر المشغلات new و delete وظائف مماثلة ويوصي بها مؤلفو تلك اللغة. [4] ومع ذلك، هناك العديد من المواقف التي لا يكون فيها استخدام / قابلاً للتطبيق، مثل كود جمع القمامة أو الكود الحساس للأداء، وقد يكون من المطلوب استخدام مزيج من و  بدلاً من المشغل ذي المستوى الأعلى . newdeletemallocnewnew

تتوفر العديد من التطبيقات المختلفة لآلية تخصيص الذاكرة الفعلية التي يستخدمها malloc . ويختلف أداؤها من حيث وقت التنفيذ والذاكرة المطلوبة.

الأساس المنطقي

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

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

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

أشار الوصف الأصلي للغة سي إلى أن callocو cfreeموجودان في المكتبة القياسية، ولكن ليس . تم إعطاء mallocالكود لتنفيذ نموذج بسيط لمدير التخزين لنظام يونكسalloc مع و freeكوظائف واجهة المستخدم، واستخدام sbrkنداء النظام لطلب الذاكرة من نظام التشغيل. [6] تقدم وثائق يونكس الإصدار السادس allocو freeكوظائف تخصيص الذاكرة منخفضة المستوى. [7] تم وصف روتينات و في mallocشكلها freeالحديث بالكامل في دليل يونكس الإصدار السابع. [8] [9]

توفر بعض المنصات استدعاءات للمكتبات أو الوظائف الجوهرية التي تسمح بالتخصيص الديناميكي وقت التشغيل من مكدس C بدلاً من الكومة (على سبيل المثال alloca()[10] ). يتم تحرير هذه الذاكرة تلقائيًا عند انتهاء الوظيفة المستدعاة.

نظرة عامة على الوظائف

يتم تعريف وظائف تخصيص الذاكرة الديناميكية في لغة C في stdlib.hheader ( cstdlibheader في لغة C++). [1]

وظيفة وصف
malloc يخصص العدد المحدد من البايتات
aligned_alloc يخصص عددًا محددًا من البايتات عند المحاذاة المحددة
realloc يزيد أو يقلل من حجم كتلة الذاكرة المحددة، وينقلها إذا لزم الأمر
calloc يخصص عددًا محددًا من البايتات ويقوم بتهيئتها إلى الصفر
free يطلق كتلة الذاكرة المحددة مرة أخرى إلى النظام

الفرق بين malloc()وcalloc()

  • malloc()يأخذ وسيطة واحدة (كمية الذاكرة المخصصة بالبايتات)، بينما calloc()يأخذ وسيطتين - عدد العناصر وحجم كل عنصر.
  • malloc()يقوم فقط بتخصيص الذاكرة، بينما calloc()يقوم بتخصيص وتعيين البايتات في المنطقة المخصصة إلى الصفر. [11]

مثال الاستخدام

إن إنشاء مجموعة مكونة من عشرة أعداد صحيحة ذات نطاق تلقائي أمر بسيط في لغة C:

مصفوفة int [ 10  

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

int * array = malloc ( 10 * sizeof ( int ));     

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

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

int * array = malloc ( 10 * sizeof ( int )); if ( array == NULL ) { fprintf ( stderr , "malloc failed \n " ); return -1 ; }     
    
   
   

عندما لم يعد البرنامج يحتاج إلى المصفوفة الديناميكية ، يجب عليه في النهاية أن يستدعيها freeلإرجاع الذاكرة التي تشغلها إلى المتجر الحر:

مجاني ( مصفوفة 

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

int * array = calloc ( 10 ، sizeof ( int ));    

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

int * arr = malloc ( 2 * sizeof ( int )); arr [ 0 ] = 1 ; arr [ 1 ] = 2 ; arr = realloc ( arr , 3 * sizeof ( int )); arr [ 2 ] = 3 ;     
  
  
     
  

لاحظ أنه يجب افتراض أن realloc قد غيّر عنوان القاعدة للكتلة (أي إذا فشل في توسيع حجم الكتلة الأصلية، وبالتالي خصص كتلة جديدة أكبر في مكان آخر ونسخ المحتويات القديمة فيها). وبالتالي، فإن أي مؤشرات إلى عناوين داخل الكتلة الأصلية لم تعد صالحة أيضًا.

سلامة النوع

mallocيعيد مؤشرًا فارغًا ( void *)، مما يشير إلى أنه مؤشر إلى منطقة ذات نوع بيانات غير معروف. يعد استخدام التحويل مطلوبًا في C++ بسبب نظام النوع القوي، في حين أن هذا ليس هو الحال في C. يمكن للمرء "تحويل" (انظر تحويل النوع ) هذا المؤشر إلى نوع معين:

int * ptr ، * ptr2 ؛ ptr = malloc ( 10 * sizeof ( * ptr )); /* بدون تحويل */ ptr2 = ( int * ) malloc ( 10 * sizeof ( * ptr )); /* مع تحويل */  
     
      

هناك مزايا وعيوب لأداء مثل هذا الصب.

مزايا الصب

  • قد يؤدي تضمين الصب إلى السماح لبرنامج C أو وظيفة C بالتجميع كـ C++.
  • يسمح الإصدار بإصدارات ما قبل عام 1989 التي mallocتم إرجاعها في الأصل char *. [12]
  • يمكن أن يساعد الصب المطور في تحديد التناقضات في حجم النوع في حالة تغير نوع مؤشر الوجهة، وخاصةً إذا تم إعلان المؤشر بعيدًا عن malloc()الاستدعاء (على الرغم من أن المترجمين الحديثين والمحللين الثابتين يمكنهم التحذير من مثل هذا السلوك دون الحاجة إلى الصب [13] ).

عيوب الصب

  • بموجب المعيار C، يكون الصب زائدا عن الحاجة.
  • قد يؤدي إضافة التحويل إلى إخفاء الفشل في تضمين الرأس stdlib.h، حيث يوجد النموذج الأولي للوظيفة لـ . [12] [14] في حالة عدم وجود نموذج أولي لـ ، يتطلب معيار C90 أن يفترض مُجمِّع C إرجاع . إذا لم يكن هناك تحويل، يتطلب C90 تشخيصًا عند تعيين هذا العدد الصحيح للمؤشر؛ ومع ذلك، مع التحويل، لن يتم إنتاج هذا التشخيص، مما يخفي خطأ. في بعض المعماريات ونماذج البيانات (مثل LP64 على أنظمة 64 بت، حيث تكون مؤشرات و 64 بت و 32 بت)، يمكن أن يؤدي هذا الخطأ في الواقع إلى سلوك غير محدد، حيث تعيد المعلنة ضمناً قيمة 32 بت بينما تعيد الوظيفة المحددة فعليًا قيمة 64 بت. اعتمادًا على اتفاقيات الاستدعاء وتخطيط الذاكرة، قد يؤدي هذا إلى تحطيم المكدس . من غير المرجح أن تمر هذه المشكلة دون أن يلاحظها أحد في المجمِّعات الحديثة، حيث لا تسمح C99 بالإعلانات الضمنية، لذلك يجب على المجمِّع إنتاج تشخيص حتى إذا افترضت return.mallocmallocmallocintlongintmallocint
  • إذا تم تغيير نوع المؤشر عند إعلانه، فقد يكون من الضروري أيضًا تغيير جميع الأسطر التي mallocيتم استدعاؤها وتحويلها.

الأخطاء الشائعة

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

الأخطاء الأكثر شيوعًا هي كما يلي: [15]

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

بالإضافة إلى ذلك، كواجهة تسبق معايير ANSI C، mallocفإن الوظائف المرتبطة بها لها سلوكيات تُركت عمدًا للتنفيذ لتحديدها بنفسها. أحدها هو تخصيص الطول الصفري، وهو مشكلة أكبر نظرًا reallocلأنه من الشائع تغيير الحجم إلى الصفر. [16] على الرغم من أن كل من POSIX ومواصفات Unix الفردية تتطلبان التعامل السليم مع تخصيصات الحجم 0 إما عن طريق الإرجاع NULLأو شيء آخر يمكن تحريره بأمان، [17] لا يُطلب من جميع المنصات الالتزام بهذه القواعد. من بين العديد من أخطاء التحرير المزدوج التي أدت إليها، كان خطأ WhatsApp RCE لعام 2019 بارزًا بشكل خاص. [18] إحدى الطرق لتغليف هذه الوظائف لجعلها أكثر أمانًا هي ببساطة التحقق من تخصيصات الحجم 0 وتحويلها إلى تخصيصات الحجم 1. (العودة NULLلها مشاكلها الخاصة: فهي تشير بخلاف ذلك إلى فشل نفاد الذاكرة. في حالة حدوث ذلك، reallocكان من الممكن أن يشير ذلك إلى أن الذاكرة الأصلية لم يتم نقلها وتحريرها، وهو ما لا يحدث مرة أخرى بالنسبة للحجم 0، مما يؤدي إلى التحرير المزدوج.) [19]

التنفيذات

يعتمد تنفيذ إدارة الذاكرة بشكل كبير على نظام التشغيل والهندسة المعمارية. توفر بعض أنظمة التشغيل مُخصصًا لـ malloc، بينما توفر أنظمة أخرى وظائف للتحكم في مناطق معينة من البيانات. غالبًا ما يتم استخدام نفس مُخصص الذاكرة الديناميكي لتنفيذ كل mallocمن وعامل newفي C++ . [20]

مبني على الكومة

كان تنفيذ المخصصات التقليدية يتم عادةً باستخدام جزء الكومة . وعادةً ما يقوم المخصص بتوسيع الكومة وتقليصها لتلبية طلبات التخصيص.

تعاني طريقة الكومة من بعض العيوب المتأصلة:

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

dlmalloc و ptmalloc

قام دوج ليا بتطوير برنامج dlmalloc للمجال العام ("Doug Lea's Malloc") كمخصص للأغراض العامة، بدءًا من عام 1987. مكتبة GNU C (glibc) مشتقة من برنامج ptmalloc ("pthreads malloc") الخاص بـ Wolfram Gloger، وهو فرع من dlmalloc مع تحسينات متعلقة بالترابط. [21] [22] [23] اعتبارًا من نوفمبر 2023، أحدث إصدار من dlmalloc هو الإصدار 2.8.6 من أغسطس 2012. [24]

dlmalloc هو مُخصص لعلامات الحدود. يتم تخصيص الذاكرة على الكومة على هيئة "قطع"، وهي بنية بيانات محاذية مكونة من 8 بايتات تحتوي على رأس، وذاكرة قابلة للاستخدام. تحتوي الذاكرة المخصصة على تكلفة إضافية تبلغ 8 أو 16 بايتًا لحجم القطعة وأعلام الاستخدام (على غرار متجه المنشطات ). تخزن القطع غير المخصصة أيضًا مؤشرات إلى قطع أخرى مجانية في منطقة المساحة القابلة للاستخدام، مما يجعل الحد الأدنى لحجم القطعة 16 بايتًا على أنظمة 32 بت و24/32 بايتًا (يعتمد على المحاذاة) على أنظمة 64 بت. [22] [24] : 2.8.6، الحد الأدنى للحجم المخصص 

يتم تجميع الذاكرة غير المخصصة في " صناديق " ذات أحجام متشابهة، ويتم تنفيذها باستخدام قائمة مزدوجة الارتباط من القطع (مع تخزين المؤشرات في المساحة غير المخصصة داخل القطعة). يتم فرز الصناديق حسب الحجم إلى ثلاث فئات: [22] [24] : هياكل البيانات المتراكبة 

  • بالنسبة للطلبات التي تقل عن 256 بايت (طلب "smallbin")، يتم استخدام مُخصص بسيط لتوزيع أفضل طاقة. إذا لم تكن هناك كتل مجانية في تلك الحاوية، يتم تقسيم كتلة من الحاوية الأعلى التالية إلى اثنتين.
  • بالنسبة للطلبات التي يبلغ حجمها 256 بايت أو أكثر ولكن أقل من عتبة mmap ، يستخدم dlmalloc منذ الإصدار 2.8.0 خوارزمية trie في المكان ("treebin"). إذا لم يكن هناك مساحة خالية متبقية لتلبية الطلب، يحاول dlmalloc زيادة حجم الكومة، عادةً عبر نداء النظام brk . تم تقديم هذه الميزة بعد فترة طويلة من إنشاء ptmalloc (من الإصدار 2.7.x)، ونتيجة لذلك فهي ليست جزءًا من glibc، الذي يرث أفضل مخصص مناسب قديم.
  • بالنسبة للطلبات التي تزيد عن عتبة mmap (طلب "largebin")، يتم تخصيص الذاكرة دائمًا باستخدام نداء النظام mmap . عادة ما تكون العتبة 128 كيلو بايت. [25] تتجنب طريقة mmap المشكلات المتعلقة بالمخازن المؤقتة الضخمة التي تحبس تخصيصًا صغيرًا في النهاية بعد انتهاء صلاحيتها، ولكنها تخصص دائمًا صفحة كاملة من الذاكرة، والتي يبلغ حجمها في العديد من البنيات 4096 بايت. [26]

يزعم مطور الألعاب أدريان ستون أن dlmalloc، كمخصص لعلامة الحدود، غير ملائم لأنظمة التحكم التي تحتوي على ذاكرة افتراضية ولكنها لا تحتوي على ترقيم الصفحات عند الطلب . وذلك لأن استدعاءات الاستدعاء المتقلصة والمتنامية ( sysmalloc/ systrim) لا يمكن استخدامها لتخصيص وتسجيل صفحات فردية من الذاكرة الافتراضية. وفي غياب الترقيم عند الطلب، يصبح التفتت مصدر قلق أكبر. [27]

jemalloc لـ FreeBSD وNetBSD

منذ FreeBSD 7.0 و NetBSD 5.0، تم استبدال التنفيذ القديم malloc( phkmallocبواسطة Poul-Henning Kamp ) بـ jemalloc، الذي كتبه Jason Evans. كان السبب الرئيسي وراء ذلك هو الافتقار إلى قابلية التوسع phkmallocمن حيث تعدد الخيوط. لتجنب التنازع على القفل، jemallocيتم استخدام "ساحات" منفصلة لكل وحدة معالجة مركزية . أظهرت التجارب التي تقيس عدد التخصيصات في الثانية في تطبيق تعدد الخيوط أن هذا يجعلها تتناسب خطيًا مع عدد الخيوط، بينما كان الأداء لكل من phkmalloc وdlmalloc متناسبًا عكسيًا مع عدد الخيوط. [28]

malloc في OpenBSD

mallocيستخدم تنفيذ OpenBSD للوظيفة mmap . بالنسبة للطلبات التي يزيد حجمها عن صفحة واحدة، يتم استرداد التخصيص بالكامل باستخدام mmap؛ يتم تعيين أحجام أصغر من مجموعات الذاكرة التي تحتفظ بها mallocضمن عدد من "صفحات الدلو"، والتي يتم تخصيصها أيضًا باستخدام mmap. [29] [ مصدر أفضل مطلوب ] عند استدعاء free، يتم تحرير الذاكرة وإلغاء تعيينها من مساحة عنوان العملية باستخدام munmap. تم تصميم هذا النظام لتحسين الأمان من خلال الاستفادة من عشوائية تخطيط مساحة العنوان وميزات صفحة الفجوة التي تم تنفيذها كجزء من mmap نداء نظام OpenBSD ، واكتشاف أخطاء الاستخدام بعد التحرير - حيث يتم إلغاء تعيين تخصيص ذاكرة كبير تمامًا بعد تحريره، يتسبب الاستخدام الإضافي في حدوث خطأ تجزئة وإنهاء البرنامج.

بدأ مشروع GrapheneOS في البداية بنقل مخصص ذاكرة OpenBSD إلى مكتبة Bionic C الخاصة بنظام Android. [30]

كنز مالوك

Hoard هو مُخصص يهدف إلى تحسين أداء تخصيص الذاكرة. ومثله كمثل مُخصص OpenBSD، يستخدم Hoard mmapالذاكرة حصريًا، ولكنه يديرها في أجزاء من 64 كيلوبايت تسمى superblocks. وتنقسم كومة Hoard منطقيًا إلى كومة عالمية واحدة وعدد من أكوام لكل معالج. بالإضافة إلى ذلك، توجد ذاكرة تخزين مؤقتة محلية للخيط يمكنها الاحتفاظ بعدد محدود من superblocks. ومن خلال التخصيص فقط من superblocks على الكومة المحلية لكل خيط أو لكل معالج، ونقل superblocks الفارغة في الغالب إلى الكومة العالمية حتى يمكن إعادة استخدامها بواسطة معالجات أخرى، يحافظ Hoard على انخفاض التجزئة مع تحقيق قابلية التوسع الخطية تقريبًا مع عدد الخيوط. [31]

ميمالوك

مُخصص ذاكرة عام مفتوح المصدر من Microsoft Research مع التركيز على الأداء. [32] تحتوي المكتبة على حوالي 11000 سطر من التعليمات البرمجية .

malloc لتخزين الخيوط مؤقتًا (tcmalloc)

يحتوي كل خيط على تخزين محلي للخيط للتخصيصات الصغيرة. بالنسبة للتخصيصات الكبيرة، يمكن استخدام mmap أو sbrk . TCMalloc، وهو malloc طورته Google، [33] لديه جمع القمامة للتخزين المحلي للخيوط الميتة. يعتبر TCMalloc أسرع بأكثر من ضعف سرعة ptmalloc في glibc للبرامج متعددة الخيوط. [34] [35]

داخل النواة

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

تجاوز malloc

نظرًا لأن mallocالرموز وأقاربها يمكن أن يكون لهم تأثير قوي على أداء البرنامج، فليس من غير المألوف تجاوز الوظائف لتطبيق معين من خلال تنفيذات مخصصة تم تحسينها لأنماط تخصيص التطبيق. لا يوفر معيار C أي طريقة للقيام بذلك، لكن أنظمة التشغيل وجدت طرقًا مختلفة للقيام بذلك من خلال استغلال الارتباط الديناميكي. إحدى الطرق هي ببساطة الارتباط في مكتبة مختلفة لتجاوز الرموز. طريقة أخرى، يستخدمها نظام Unix V.3 ، هي إنشاء مؤشرات mallocوظيفية freeيمكن للتطبيق إعادة تعيينها إلى وظائف مخصصة. [37]

الشكل الأكثر شيوعًا في الأنظمة المشابهة لـ POSIX هو تعيين متغير البيئة LD_PRELOAD بمسار المخصص، بحيث يستخدم الرابط الديناميكي هذا الإصدار من malloc/calloc/free بدلاً من تنفيذ libc.

حدود حجم التخصيص

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

من الناحية النظرية، يجب أن يكون أكبر عدد هو القيمة القصوى التي يمكن الاحتفاظ بها في size_tنوع ما، وهو عدد صحيح غير موقّع يعتمد على التنفيذ ويمثل حجم منطقة الذاكرة. في معيار C99 وما بعده، يتوفر هذا العدد على هيئة SIZE_MAXثابت من . على الرغم من عدم ضمانه بواسطة ISO C ، إلا أنه عادةً ما يكون . <stdint.h>2^(CHAR_BIT * sizeof(size_t)) - 1

في أنظمة glibc، أكبر كتلة ذاكرة ممكنة mallocيمكن تخصيصها هي نصف هذا الحجم فقط، أي . [38]2^(CHAR_BIT * sizeof(ptrdiff_t) - 1) - 1

الإضافات والبدائل

قد تأتي تطبيقات مكتبة C المرفقة مع أنظمة التشغيل والمُجمِّعات المختلفة مع بدائل وإضافات للواجهة القياسية malloc. ومن بين هذه البدائل والإضافات:

  • alloca، والتي تخصص عددًا مطلوبًا من البايتات على مكدس النداء . لا توجد وظيفة إلغاء تخصيص مقابلة، حيث يتم عادةً إلغاء تخصيص الذاكرة بمجرد عودة الوظيفة المستدعية. allocaكانت موجودة على أنظمة يونكس منذ وقت مبكر من 32/V (1978)، ولكن استخدامها يمكن أن يكون إشكاليًا في بعض السياقات (على سبيل المثال، المضمنة). [39] على الرغم من دعمها من قبل العديد من المترجمين، إلا أنها ليست جزءًا من معيار ANSI-C وبالتالي قد لا تكون محمولة دائمًا. قد تتسبب أيضًا في حدوث مشكلات بسيطة في الأداء: فهي تؤدي إلى إطارات مكدس ذات حجم متغير، بحيث يلزم إدارة كل من مؤشرات المكدس والإطار (مع إطارات المكدس ذات الحجم الثابت، يكون أحد هذه المؤشرات زائدًا عن الحاجة). [40] قد تزيد التخصيصات الأكبر أيضًا من خطر السلوك غير المحدد بسبب تجاوز المكدس . [41] قدمت C99 مصفوفات ذات طول متغير كآلية بديلة لتخصيص المكدس - ومع ذلك، تم تهميش هذه الميزة لتصبح اختيارية في معيار C11 اللاحق .
  • يحدد POSIX دالة posix_memalignتقوم بتخصيص الذاكرة بمحاذاة محددة من قبل المتصل. يتم إلغاء تخصيص الذاكرة باستخدام free، [42] لذا فإن التنفيذ عادة ما يحتاج إلى أن يكون جزءًا من مكتبة malloc.

انظر أيضا

مراجع

  1. ^ ab 7.20.3 وظائف إدارة الذاكرة (PDF) . مواصفات ISO/IEC 9899:1999 (تقرير فني). ص. 313.
  2. ^ Summit, Steve. "الفصل 11: تخصيص الذاكرة". ملاحظات برمجة C. تم الاسترجاع في 11 يوليو 2020 .
  3. ^ "aligned_alloc(3) - صفحة دليل Linux".
  4. ^ Stroustrup, Bjarne (2008). Programming: Principles and Practice Using C++ . Addison Wesley. p. 1009. ISBN 978-0-321-54372-1.
  5. ^ "gcc manual". gnu.org . تم الاسترجاع في 2008-12-14 .
  6. ^ Brian W. Kernighan, Dennis M. Ritchie, The C Programming Language , Prentice-Hall, 1978; يصف القسم 7.9 (صفحة 156) callocو cfree، ويصف القسم 8.7 (صفحة 173) تنفيذًا لـ allocو free.
  7. ^ alloc(3)  –  دليل مبرمج يونكس الإصدار 6
  8. ^ malloc(3)  –  دليل مبرمج يونكس الإصدار 7
  9. ^ مجهول، دليل مبرمج يونكس، المجلد 1 ، هولت رينهارت ووينستون، 1983 (حقوق الطبع والنشر محفوظة لشركة بيل تيليفون لابوراتوريز، 1983، 1979)؛ manالصفحة الخاصة mallocبما سبق موجودة في الصفحة 275.
  10. ^ alloca(3)  –  دليل وظائف مكتبة FreeBSD
  11. ^ calloc(3)  –  دليل مبرمج لينكس – وظائف المكتبة
  12. ^ ab "Casting malloc". Cprogramming.com . تم الاسترجاع في 2007-03-09 .
  13. ^ "clang: lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp Source File". clang.llvm.org . تم الاسترجاع في 2018-04-01 .
  14. ^ "comp.lang.c FAQ list · Question 7.7b". C-FAQ . تم الاسترجاع في 2007-03-09 .
  15. ^ Reek, Kenneth (1997-08-04). Pointers on C (طبعة واحدة). Pearson. ISBN 9780673999863.
  16. ^ "MEM04-C. احذر من التخصيصات ذات الطول الصفري - SEI CERT C Coding Standard - Confluence". wiki.sei.cmu.edu .
  17. ^ "POSIX.1-2017: malloc". pubs.opengroup.org . تم الاسترجاع في 2019-11-29 .
  18. ^ Awakened (2019-10-02). "كيف يتحول خطأ مزدوج في WhatsApp إلى RCE" . تم الاسترجاع في 2019-11-29 .
  19. ^ Felker, Rich [@RichFelker] (2019-10-03). "واو. كان سلوك RCE في WhatsApp خاطئًا بالنسبة إلى realloc(p,0) الذي تصر عليه العديد من التطبيقات" ( Tweet ) . تم الاسترجاع في 2022-08-06 – عبر Twitter .
  20. ^ ألكسندرسكو، أندريه (2001). تصميم C++ الحديث: البرمجة العامة وأنماط التصميم المطبقة . أديسون ويسلي. ص 78.
  21. ^ "الصفحة الرئيسية لـWolfram Gloger's malloc". malloc.de . تم الاسترجاع في 2018-04-01 .
  22. ^ abc Kaempf, Michel (2001). "Vudo malloc tricks". Phrack (57): 8. مؤرشف من الأصل في 2009-01-22 . تم الاسترجاع في 2009-04-29 .
  23. ^ "Glibc: Malloc Internals". sourceware.org Trac . تم الاسترجاع في 2019-12-01 .
  24. ^ abc Lee, Doug. "A Memory Allocator" . تم الاسترجاع في 2019-12-01 .HTTP لرمز المصدر
  25. ^ "معلمات قابلة للضبط بواسطة Malloc". GNU . تم الاسترجاع في 2009-05-02 .
  26. ^ ساندرسون، بروس (2004-12-12). "RAM، والذاكرة الافتراضية، وملف الصفحات وكل تلك الأشياء". تعليمات ودعم Microsoft.
  27. ^ ستون، أدريان. "الفجوة التي لا يستطيع دلمالوك ملؤها". Game Angst . تم الاسترجاع في 2019-12-01 .
  28. ^ إيفانز، جيسون (2006-04-16). "تنفيذ malloc(3) متزامن وقابل للتطوير لنظام FreeBSD" (PDF) . تم الاسترجاع في 2012-03-18 .
  29. ^ "libc/stdlib/malloc.c". مرجع BSD المتبادل، OpenBSD src/lib/ .
  30. ^ "التاريخ | GrapheneOS". grapheneos.org . تم الاسترجاع في 2023-03-02 .
  31. ^ Berger, ED; McKinley, KS ; Blumofe, RD; Wilson, PR (نوفمبر 2000). Hoard: A Scalable Memory Allocator for Multithreaded Applications (PDF) . ASPLOS -IX. وقائع المؤتمر الدولي التاسع حول الدعم المعماري للغات البرمجة وأنظمة التشغيل . ص 117-128. CiteSeerX 10.1.1.1.4174 . doi :10.1145/378993.379232. ISBN  1-58113-317-0.
  32. ^ مايكروسوفت تطلق malloc() المحسّن كمصدر مفتوح - Slashdot
  33. ^ الصفحة الرئيسية لـ TCMalloc
  34. ^ Ghemawat, Sanjay; Menage, Paul; TCMalloc : تخزين الخيوط في Malloc
  35. ^ Callaghan, Mark (2009-01-18). "MySQL High Availability: Double sysbench throughput with TCMalloc". Mysqlha.blogspot.com . تم الاسترجاع في 2011-09-18 .
  36. ^ "kmalloc()/kfree() include/linux/slab.h". People.netfilter.org . تم الاسترجاع في 2011-09-18 .
  37. ^ Levine, John R. (2000) [أكتوبر 1999]. "الفصل 9: المكتبات المشتركة". أدوات الربط والتحميل. سلسلة مورجان كوفمان في هندسة البرمجيات والبرمجة (طبعة واحدة). سان فرانسيسكو، الولايات المتحدة الأمريكية: مورجان كوفمان . رقم ISBN 1-55860-496-0. OCLC  42413382. مؤرشف من الأصل في 2012-12-05 . تم الاسترجاع 2020-01-12 .الكود: [1][2] الأخطاء: [3]
  38. ^ "malloc: جعل malloc يفشل مع الطلبات الأكبر من PTRDIFF_MAX". Sourceware Bugzilla . 2019-04-18 . تم الاسترجاع في 2020-07-30 .
  39. ^ "لماذا لا يُعتبر استخدام alloca() ممارسة جيدة؟". stackoverflow.com . تم الاسترجاع في 2016-01-05 .
  40. ^ Amarasinghe, Saman; Leiserson, Charles (2010). "6.172 Performance Engineering of Software Systems, Lecture 10". MIT OpenCourseWare . معهد ماساتشوستس للتكنولوجيا. مؤرشف من الأصل في 2015-06-22 . تم الاسترجاع في 2015-01-27 .
  41. ^ "alloca(3) - صفحة دليل Linux". man7.org . تم الاسترجاع في 2016-01-05 .
  42. ^ posix_memalign  – مرجع واجهات النظام، مواصفات UNIX الفردية ، الإصدار 4 من مجموعة Open Group
  • تعريف malloc في معيار IEEE Std 1003.1
  • ليا، دوج ؛ تصميم أساس مُخصص glibc
  • جلوجر، ولفرام. الصفحة الرئيسية بتمالوك
  • بيرجر، إيمري؛ الصفحة الرئيسية لموقع The Hoard
  • دوغلاس، نيل؛ الصفحة الرئيسية لموقع nedmalloc
  • إيفانز، جيسون؛ الصفحة الرئيسية لـ jemalloc
  • جوجل؛ الصفحة الرئيسية لـ tcmalloc
  • خوارزميات تخصيص الذاكرة البسيطة على مجتمع OSDEV
  • مايكل، ماجد م.؛ تخصيص الذاكرة الديناميكية القابلة للتطوير والخالية من الأقفال
  • بارتليت، جوناثان؛ إدارة الذاكرة الداخلية – الاختيارات، والتنازلات، وتنفيذات التخصيص الديناميكي
  • صفحة ويكي تقليل الذاكرة (GNOME) تحتوي على الكثير من المعلومات حول إصلاح malloc
  • مسودة قياسية C99، بما في ذلك TC1/TC2/TC3
  • بعض المراجع المفيدة حول لغة C
  • ISO/IEC 9899 – لغات البرمجة – C
  • فهم glibc malloc
تم الاسترجاع من "https://en.wikipedia.org/w/index.php?title=تخصيص_الذاكرة_الديناميكي_باستخدام_لغة_C&oldid=1253063187"
Original text
Rate this translation
Your feedback will be used to help improve Google Translate