您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“C指針原理之垃圾回收與內存泄露的示例分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“C指針原理之垃圾回收與內存泄露的示例分析”這篇文章吧。
一、內存泄露
1、正常的鏈表操作
下面程序建立一個10元素的鏈表,輸出它們的節點,每個節點是一個員工的工號和年齡。最后刪除每個節點,釋放列表。
dp@dp:~/memorytest % cat 1.c #include <stdlib.h> #include <stdio.h> //code:myhaspl@myhaspl.com //author:myhaspl //date:2014-01-10 typedef struct listnode mynode; struct listnode{ mynode *next; int number; int age; }; mynode *addnode(mynode *prevnd,int number,int age){ mynode *ndtemp=(mynode*)malloc(sizeof(mynode)); prevnd->next=ndtemp; ndtemp->number=number; ndtemp->age=age; ndtemp->next=NULL; return ndtemp; } mynode *initlist(){ mynode *temp=(mynode*)malloc(sizeof(mynode)); temp->number=0; temp->age=0; temp->next=NULL; return temp; } int main(){ mynode *mylist=initlist(); mynode *mytempnd=mylist; int i=0;f懸掛指針 for(i=0;i<10;i++){ mytempnd=addnode(mytempnd,i,20+i); } //下面是正常的鏈表操作 //先輸出鏈表元素 for (mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d\n",mytempnd->number,mytempnd->age); } //然后刪除鏈表中的所有元素 mynode* oldtmpnd; for (mytempnd=mylist->next;mytempnd!=NULL;){ printf("delete id:%d\n",mytempnd->number); oldtmpnd=mytempnd; mytempnd=mytempnd->next; free(oldtmpnd); } free(mylist); return 0; }
下面是程序運行效果
dp@dp:~/memorytest % gcc 1.c -o mytest dp@dp:~/memorytest % ./mytest id:0,age:20 id:1,age:21 id:2,age:22 id:3,age:23 id:4,age:24 id:5,age:25 id:6,age:26 id:7,age:27 id:8,age:28 id:9,age:29 delete id:0 delete id:1 delete id:2 delete id:3 delete id:4 delete id:5 delete id:6 delete id:7 delete id:8 delete id:9 dp@dp:~/memorytest %
下面演示了垃圾的形成,這是內存泄露的一種方式,即在鏈表中,某些節點與鏈表中的其它節點失去聯系,導致無法刪除,下面故意讓第4個結點的next指針指向null,失去與后面6個元素的聯系。
dp@dp:~/memorytest % cat 1.c #include <stdlib.h> #include <stdio.h> //code:myhaspl@myhaspl.com //author:myhaspl //date:2014-01-10 typedef struct listnode mynode; struct listnode{ mynode *next; int number; int age; }; mynode *addnode(mynode *prevnd,int number,int age){ mynode *ndtemp=(mynode*)malloc(sizeof(mynode)); prevnd->next=ndtemp; ndtemp->number=number; ndtemp->age=age; ndtemp->next=NULL; return ndtemp; } mynode *initlist(){ mynode *temp=(mynode*)malloc(sizeof(mynode)); temp->number=0; temp->age=0; temp->next=NULL; return temp; } int main(){ mynode *mylist=initlist(); mynode *mytempnd=mylist; int i=0; for(i=0;i<10;i++){ mytempnd=addnode(mytempnd,i,20+i); } //下面是正常的鏈表操作 //先輸出鏈表元素 for (mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d\n",mytempnd->number,mytempnd->age); } //然后刪除鏈表中的所有元素 for (mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("delete id:%d\n",mytempnd->number); free(mytempnd); } free(mylist); //下面是形成內存泄露第一種情況-垃圾的演示 //生成并輸出鏈表,這個與前面相同 mylist=initlist(); mytempnd=mylist; i=0; for(i=0;i<10;i++){ mytempnd=addnode(mytempnd,i,20+i); } for (mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d\n",mytempnd->number,mytempnd->age); } //刪除鏈表,我們故意留下后面6個鏈表節點無法刪除,導致后面6個鏈表節點形成垃圾 int j=0; for (mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ if (++j>3){ mytempnd->next=NULL; break; } } for (mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("delete id:%d\n",mytempnd->number); free(mytempnd); j++; } return 0; }
下面是程序運行效果
dp@dp:~/memorytest % gcc 1.c -o mytest dp@dp:~/memorytest % ./mytest id:0,age:20 id:1,age:21 id:2,age:22 id:3,age:23 id:4,age:24 id:5,age:25 id:6,age:26 id:7,age:27 id:8,age:28 id:9,age:29 delete id:0 delete id:1 delete id:2 delete id:3 delete id:4 delete id:5 delete id:6 delete id:7 delete id:8 delete id:9 id:0,age:20 id:1,age:21 id:2,age:22 id:3,age:23 id:4,age:24 id:5,age:25 id:6,age:26 id:7,age:27 id:8,age:28 id:9,age:29 delete id:0 delete id:1 delete id:2 delete id:3 dp@dp:~/memorytest %
3、懸掛指針
一個指針不為空,但是指向一個無效的地址或耒知對象的地址,則這樣的指針稱為懸掛指針。
dp@dp:~/memorytest % cat 2.c #include <stdio.h> #include <stdlib.h> //code:myhaspl@myhaspl.com //author:myhaspl //date:2014-01-10 typedef struct listnode mynode; struct listnode{ mynode *next; int number; int age; }; mynode *addnode(mynode *prevnd,int number,int age){ mynode *ndtemp=(mynode*)malloc(sizeof(mynode)); prevnd->next=ndtemp; ndtemp->number=number; ndtemp->age=age; ndtemp->next=NULL; return ndtemp; } mynode *initlist(){ mynode *temp=(mynode*)malloc(sizeof(mynode)); temp->number=0; temp->age=0; temp->next=NULL; return temp; } int main(){ mynode *mylist=initlist(); mynode *mytempnd=mylist; int i=0; for(i=0;i<10;i++){ mytempnd=addnode(mytempnd,i,20+i); } //下面是正常的鏈表操作 //先輸出鏈表元素 for (mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d\n",mytempnd->number,mytempnd->age); } //然后刪除鏈表中的所有元素 mynode* oldtmpnd; for (mytempnd=mylist->next;mytempnd!=NULL;){ printf("delete id:%d\n",mytempnd->number); oldtmpnd=mytempnd; mytempnd=mytempnd->next; free(oldtmpnd); } free(mylist); //下面是形成內存泄露第二種情況-懸掛指針的演示 //生成并輸出鏈表,這個與前面相同 mylist=initlist(); mytempnd=mylist; i=0; for(i=0;i<10;i++){ mytempnd=addnode(mytempnd,i,20+i); } for (mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d\n",mytempnd->number,mytempnd->age); } //我們故意刪除鏈表后面的4個節點,但是讓第6個元素的next指向的地址無效, //仍指向已經刪除的第7個節點,導致懸掛指針 printf ("-------------------------\n"); int j=0; for (mytempnd=mylist->next;mytempnd!=NULL;){ oldtmpnd=mytempnd; mytempnd=mytempnd->next; if (++j>6){ printf("delete id:%d\n",oldtmpnd->number); free(oldtmpnd); } } return 0; }
執行程序
dp@dp:~/memorytest % gcc 2.c -o mytest dp@dp:~/memorytest % ./mytest id:0,age:20 id:1,age:21 id:2,age:22 id:3,age:23 id:4,age:24 id:5,age:25 id:6,age:26 id:7,age:27 id:8,age:28 id:9,age:29 delete id:0 delete id:1 delete id:2 delete id:3 delete id:4 delete id:5 delete id:6 delete id:7 delete id:8 delete id:9 id:0,age:20 id:1,age:21 id:2,age:22 id:3,age:23 id:4,age:24 id:5,age:25 id:6,age:26 id:7,age:27 id:8,age:28 id:9,age:29 delete id:6 delete id:7 delete id:8 delete id:9
但是注意free函數表示釋放,這個釋放指的是把這段內存標記成可用狀態,或者說,沒有人在用這段內存了,也就是意味著如果這段內存如果沒有被操作系統重新使用,里面的數據還存在,如果被操作系統分配給其它程序或本程序的其它內存塊申請之用,則數據會被清空。
3、下面是形成內存泄露第三種情況-共享的演示,多個指針指向同一個內存,這個內存因為某個指針不再使用的原因刪除,導致其它指針指向一個無效地址
dp@dp:~/memorytest % cat 2.c #include <stdio.h> #include <stdlib.h> //code:myhaspl@myhaspl.com //author:myhaspl //date:2014-01-10 typedef struct listnode mynode; struct listnode{ mynode *next; char *data; int number; int age; }; mynode *addnode(mynode *prevnd,int number,int age,char *data){ mynode *ndtemp=(mynode*)malloc(sizeof(mynode)); prevnd->next=ndtemp; ndtemp->number=number; ndtemp->age=age; ndtemp->data=data; ndtemp->next=NULL; return ndtemp; } mynode *initlist(){ mynode *temp=(mynode*)malloc(sizeof(mynode)); temp->number=0; temp->age=0; temp->data=NULL; temp->next=NULL; return temp; } int main(){ //下面是形成內存泄露第三種情況-共享的演示,多個指針指向同一個內存,這個內存因為某個指針不再使用的原因刪除, //生成并輸出鏈表,生成1個鏈表(共3個元素),元素的data都指向同一個內存塊 mynode *mylist=initlist(); mynode *mytempnd=mylist; char *mydata=(char *)malloc(100); const char *strsrc="helloworld"; strcpy(mydata,strsrc); int i=0; for(i=0;i<3;i++){ mytempnd=addnode(mytempnd,i,20+i,mydata); } for (mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d,data:%s\n",mytempnd->number,mytempnd->age,mytempnd->data); } //下面將導致共享的內存釋放,但仍有2個結點指向這個內存,這將導致內存泄露 //我們故意刪除最后一個節點,并釋放最后一個結點的data指針指向的內存 printf ("-------------------------\n"); mynode *oldtmpnd; for (mytempnd=mylist->next;mytempnd!=NULL;){ oldtmpnd=mytempnd; mytempnd=mytempnd->next; if (mytempnd==NULL){ printf("delete id:%d\n",oldtmpnd->number); free(oldtmpnd->data); free(oldtmpnd); } } return 0; }
執行程序:
dp@dp:~/memorytest % gcc 2.c -o mytest 2.c: In function 'main': 2.c:37: warning: incompatible implicit declaration of built-in function 'strcpy' dp@dp:~/memorytest % ./mytest id:0,age:20,data:helloworld id:1,age:21,data:helloworld id:2,age:22,data:helloworld delete id:2 dp@dp:~/memorytest %
以上是“C指針原理之垃圾回收與內存泄露的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。