سؤال

الرجاء المساعدة :) نظام التشغيل :لينكس

حيث في" النوم(1000) ؛ "، في هذا الوقت" أعلى (عرض المهام لينكس) " كتب لي 7.7 ٪ استخدام م.فالغريند :لم يتم العثور على تسرب الذاكرة.

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

آسف على لغتي الإنجليزية السيئة ، شكرا


~ # tmp_soft
For : Is it free??  no
Is it free??  yes
For 0 
For : Is it free??  no
Is it free??  yes
For 1 
END : Is it free??  yes
END 

~ #top
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                
23060 root      20   0  155m 153m  448 S    0  7.7   0:01.07 tmp_soft    

المصدر الكامل :تمب_ سوفت.c

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

struct cache_db_s
{
 int       table_update;
 struct    cache_db_s * p_next;
};

void free_cache_db (struct cache_db_s ** cache_db)
{
 struct cache_db_s * cache_db_t;
 while (*cache_db != NULL)
 {
  cache_db_t = *cache_db;
  *cache_db = (*cache_db)->p_next;
  free(cache_db_t);
  cache_db_t = NULL;
 }
 printf("Is it free??  %s\n",*cache_db==NULL?"yes":"no");
}

void make_cache_db (struct cache_db_s ** cache_db)
{
 struct cache_db_s * cache_db_t = NULL;
 int n = 10000000;

 for (int i=0; i = n; i++)
 {
  if ((cache_db_t=malloc(sizeof(struct cache_db_s)))==NULL) {
   printf("Error : malloc 1 -> cache_db_s (no free memory) \n");
   break;
  }
  memset(cache_db_t, 0, sizeof(struct cache_db_s));

  cache_db_t->table_update = 1; // tmp 

  cache_db_t->p_next = *cache_db;
  *cache_db = cache_db_t;
  cache_db_t = NULL;
 }
}

int main(int argc, char **argv)
{
 struct cache_db_s * cache_db = NULL;

 for (int ii=0; ii  2; ii++) {
  make_cache_db(&cache_db);
  printf("For : Is it free??  %s\n",cache_db==NULL?"yes":"no");
  free_cache_db(&cache_db);
  printf("For %d \n", ii);
 }

 printf("END : Is it free??  %s\n",cache_db==NULL?"yes":"no");
 printf("END \n");
 sleep(1000);
 return 0;
}
هل كانت مفيدة؟

المحلول

إذا كنت تحاول تحديد ما إذا كان البرنامج الخاص بك لديه تسرب الذاكرة ، ثم top ليست الأداة المناسبة لهذا المنصب (valrind هو).

top يظهر استخدام الذاكرة كما يراها نظام التشغيل.حتى لو اتصلت free, ، ليس هناك ما يضمن أن الذاكرة المحررة ستعود إلى نظام التشغيل.عادة ، فإنه لن.ومع ذلك ، فإن الذاكرة تصبح "حرة" بمعنى أن العملية الخاصة بك يمكن استخدامها لتخصيصات لاحقة.

تحرير إذا كان لديك libc يدعم ذلك ، يمكنك محاولة تجريب M_TRIM_THRESHOLD.حتى إذا اتبعت هذا المسار ، فسيكون الأمر صعبا (كتلة واحدة مستخدمة تجلس بالقرب من الجزء العلوي من الكومة ستمنع تحرير كل الذاكرة الخالية أسفلها إلى نظام التشغيل).

نصائح أخرى

لأسباب جيدة، لا توجد مخصص الذاكرة تقريبا إرجاع كتل إلى نظام التشغيل

لا يمكن إزالة الذاكرة إلا من برنامجك في وحدات الصفحات، وحتى أنه من غير المرجح أن يلاحظ ذلك.

caloc (3) و malloc (3) يتفاعل مع kernel للحصول على الذاكرة، إذا لزم الأمر. ولكن جدا، غير قليل جدا من تطبيقات مجانية (3) من أي وقت مضى إرجاع الذاكرة إلى kernel 1

حتى إذا أرادت حرة () إرجاع الذاكرة إلى النظام، فسيحتاج إلى صفحة ذاكرة واحدة على الأقل من أجل الحصول على النواة لتحمي المنطقة فعليا، لذلك فإن إطلاق كتلة صغيرة سيؤدي إلا إلى تغيير الحماية إذا كان الأمر آخر كتلة صغيرة في صفحة.

نظرية العملية

حتى يحصل maloc (3) على الذاكرة من kernel عندما يحتاجها، في نهاية المطاف في وحدات مضاعفات الصفحة المنفصلة. يتم تقسيم هذه الصفحات أو توحيدها كما يتطلب البرنامج. maloc والتعاون المجاني للحفاظ على دليل. إنهم يتجهون كتل مجانية مجاورة عندما يكون من الممكن أن تكون قادرا على توفير كتل كبيرة. قد يتضمن الدليل أو لا ينطوي على استخدام الذاكرة في كتل تحرير لتشكيل قائمة مرتبطة. (البديل هو أكثر الذاكرة مشتركة بعض الشيء والترحيل، ويشمل تخصيص الذاكرة على وجه التحديد لهذا الدليل.) ليس لديك القليل من القدرة على فرض الوصول إلى كتل الفردية حتى عند تجميع رمز تصحيح الأخطاء الخاص والاختياري البرنامج.


1. حقيقة أن بعض التطبيقات القليلة للغاية من المحاولة المجانية () لم يعد الذاكرة إلى النظام ليست على الإطلاق بسبب تجنب المنفذين.

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

مجاني عموما () لا يعيد الذاكرة الفعلية إلى نظام التشغيل، لا يزال يتم تعيينه في الذاكرة الظاهرية في العملية الخاصة بك.إذا قمت بتخصيص جزء كبير من الذاكرة، فقد تخصيص LIBC بواسطة MMAP ()؛ثم إذا كنت تحررها، فقد تحدد LIBC الذاكرة إلى نظام التشغيل من قبل Munmap ()، في هذه الحالة، سيعرض Top أن استخدام ذاكرة الخاص بك ينخفض.

لذلك، إذا كنت تريد تحرير الذاكرة إلى نظام التشغيل بشكل صريح، فيمكنك استخدام mmap () / munmap ().

عندما كنت free() الذاكرة ، يتم إرجاعها إلى مجموعة ذاكرة مكتبة سي القياسية ، ولا يتم إرجاعها إلى نظام التشغيل.في رؤية نظام التشغيل ، كما تراه من خلال top, ، لا تزال العملية "تستخدم" هذه الذاكرة.ضمن هذه العملية ، شكلت مكتبة ج للذاكرة ويمكن أن يعود نفس المؤشر من malloc() في المستقبل.

سأشرح ذلك أكثر مع بداية مختلفة:

أثناء المكالمات إلى malloc, ، قد يحدد تطبيق المكتبة القياسي أن العملية لا تحتوي على ذاكرة مخصصة كافية من نظام التشغيل.في ذلك الوقت ، ستقوم المكتبة بإجراء مكالمة نظام لتلقي المزيد من الذاكرة من نظام التشغيل إلى العملية (على سبيل المثال, sbrk() أو VirtualAlloc() يدعو النظام على يونكس أو ويندوز ، على التوالي).

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

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

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

مشكلتان:

  • في make_cache_db(), ، الخط

    for (int i=0; i = n; i++)
    

    ربما يجب أن تقرأ

    for (int i=0; i<n; i++)
    

    خلاف ذلك ، عليك تخصيص واحد فقط cache_db_s عقدة.

  • الطريقة التي تعين بها cache_db في make_cache_db() يبدو أن عربات التي تجرها الدواب.يبدو أن نيتك هي إرجاع مؤشر إلى العنصر الأول من القائمة المرتبطة;ولكن لأنك إعادة تعيين cache_db في كل تكرار للحلقة ، سينتهي بك الأمر بإرجاع مؤشر إلى الاخير عنصر القائمة.

    إذا قمت لاحقا بتحرير القائمة باستخدام free_cache_db(), ، سيؤدي ذلك إلى تسرب الذاكرة.في الوقت الحالي ، على الرغم من ذلك ، يتم إخفاء هذه المشكلة عن طريق الخطأ الموضح في النقطة النقطية السابقة ، مما يؤدي إلى تخصيص قوائم بطول 1 فقط.

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

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