首页 > 编程 > C > 正文

C指针原理教程之垃圾回收-内存泄露

2020-01-26 13:32:28
字体:
来源:转载
供稿:网友

一、内存泄露

1、正常的链表操作

下面程序建立一个10元素的链表,输出它们的节点,每个节点是一个员工的工号和年龄。最后删除每个节点,释放列表。

dp@dp:~/memorytest % cat 1.c#include <stdlib.h>#include <stdio.h>//code:myhaspl@myhaspl.com//author:myhaspl//date:2014-01-10typedef 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 mytestdp@dp:~/memorytest % ./mytestid:0,age:20id:1,age:21id:2,age:22id:3,age:23id:4,age:24id:5,age:25id:6,age:26id:7,age:27id:8,age:28id:9,age:29delete id:0delete id:1delete id:2delete id:3delete id:4delete id:5delete id:6delete id:7delete id:8delete id:9dp@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-10typedef 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 mytestdp@dp:~/memorytest % ./mytestid:0,age:20id:1,age:21id:2,age:22id:3,age:23id:4,age:24id:5,age:25id:6,age:26id:7,age:27id:8,age:28id:9,age:29delete id:0delete id:1delete id:2delete id:3delete id:4delete id:5delete id:6delete id:7delete id:8delete id:9id:0,age:20id:1,age:21id:2,age:22id:3,age:23id:4,age:24id:5,age:25id:6,age:26id:7,age:27id:8,age:28id:9,age:29delete id:0delete id:1delete id:2delete id:3dp@dp:~/memorytest %

3、悬挂指针

一个指针不为空,但是指向一个无效的地址或耒知对象的地址,则这样的指针称为悬挂指针。

dp@dp:~/memorytest % cat 2.c#include <stdio.h>#include <stdlib.h>//code:myhaspl@myhaspl.com//author:myhaspl//date:2014-01-10typedef 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 mytestdp@dp:~/memorytest % ./mytestid:0,age:20id:1,age:21id:2,age:22id:3,age:23id:4,age:24id:5,age:25id:6,age:26id:7,age:27id:8,age:28id:9,age:29delete id:0delete id:1delete id:2delete id:3delete id:4delete id:5delete id:6delete id:7delete id:8delete id:9id:0,age:20id:1,age:21id:2,age:22id:3,age:23id:4,age:24id:5,age:25id:6,age:26id:7,age:27id:8,age:28id:9,age:29delete id:6delete id:7delete id:8delete 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-10typedef 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 mytest2.c: In function 'main':2.c:37: warning: incompatible implicit declaration of built-in function 'strcpy'dp@dp:~/memorytest % ./mytestid:0,age:20,data:helloworldid:1,age:21,data:helloworldid:2,age:22,data:helloworlddelete id:2dp@dp:~/memorytest % 

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选