C指针原理(28)-垃圾回收-内存泄露
一、內存泄露
1、正常的鏈表操作
下面程序建立一個10元素的鏈表,輸出它們的節點,每個節點是一個員工的工號和年齡。最后刪除每個節點,釋放列表。
dp@dp:~/memorytest % cat 1.c
#include <stdlib.h> #include <stdio.h>//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>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>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>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指针原理(28)-垃圾回收-内存泄露的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C指针原理(27)-编译基本原理-语法树
- 下一篇: 联想sr950配置raid卡_联想Thi