C指针原理(28)-垃圾回收-内存泄露
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C指针原理(28)-垃圾回收-内存泄露相关的知识,希望对你有一定的参考价值。
一、内存泄露
1、正常的链表操作
下面程序建立一个10元素的链表,输出它们的节点,每个节点是一个员工的工号和年龄。最后删除每个节点,释放列表。
[email protected]:~/memorytest?%?cat?1.c
#include <stdlib.h>
#include <stdio.h>
//code:[email protected]
//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
",mytempnd->number,mytempnd->age);
}
//然后删除链表中的所有元素
mynode* oldtmpnd;
for (mytempnd=mylist->next;mytempnd!=NULL;){
printf("delete id:%d
",mytempnd->number);
oldtmpnd=mytempnd;
mytempnd=mytempnd->next;
free(oldtmpnd);
}
free(mylist);
return 0;
}
下面是程序运行效果
[email protected]:~/memorytest?%?gcc?1.c?-o?mytest
[email protected]:~/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
[email protected]:~/memorytest?%?
下面演示了垃圾的形成,这是内存泄露的一种方式,即在链表中,某些节点与链表中的其它节点失去联系,导致无法删除,下面故意让第4个结点的next指针指向null,失去与后面6个元素的联系。
[email protected]:~/memorytest?%?cat?1.c
#include <stdlib.h>
#include <stdio.h>
//code:[email protected]
//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
",mytempnd->number,mytempnd->age);
}
//然后删除链表中的所有元素
for (mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){
printf("delete id:%d
",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
",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
",mytempnd->number);
free(mytempnd);
j++;
}
return 0;
}
下面是程序运行效果
[email protected]:~/memorytest?%?gcc?1.c?-o?mytest
[email protected]:~/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
[email protected]:~/memorytest?%
3、悬挂指针
一个指针不为空,但是指向一个无效的地址或耒知对象的地址,则这样的指针称为悬挂指针。
[email protected]:~/memorytest?%?cat?2.c
#include <stdio.h>
#include <stdlib.h>
//code:[email protected]
//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
",mytempnd->number,mytempnd->age);
}
//然后删除链表中的所有元素
mynode* oldtmpnd;
for (mytempnd=mylist->next;mytempnd!=NULL;){
printf("delete id:%d
",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
",mytempnd->number,mytempnd->age);
}
//我们故意删除链表后面的4个节点,但是让第6个元素的next指向的地址无效,
//仍指向已经删除的第7个节点,导致悬挂指针
printf ("-------------------------
");
int j=0;
for (mytempnd=mylist->next;mytempnd!=NULL;){
oldtmpnd=mytempnd;
mytempnd=mytempnd->next;
if (++j>6){
printf("delete id:%d
",oldtmpnd->number);
free(oldtmpnd);
}
}
return 0;
}
执行程序
[email protected]:~/memorytest?%?gcc?2.c?-o?mytest
[email protected]:~/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、下面是形成内存泄露第三种情况-共享的演示,多个指针指向同一个内存,这个内存因为某个指针不再使用的原因删除,导致其它指针指向一个无效地址
[email protected]:~/memorytest?%?cat?2.c
#include?<stdio.h>
#include?<stdlib.h>
//code:[email protected]
//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
",mytempnd->number,mytempnd->age,mytempnd->data);
??????? }
//下面将导致共享的内存释放,但仍有2个结点指向这个内存,这将导致内存泄露
//我们故意删除最后一个节点,并释放最后一个结点的data指针指向的内存
printf?("-------------------------
");
mynode?*oldtmpnd;
for?(mytempnd=mylist->next;mytempnd!=NULL;){
oldtmpnd=mytempnd;
mytempnd=mytempnd->next;
if?(mytempnd==NULL){
printf("delete?id:%d
",oldtmpnd->number);
free(oldtmpnd->data);
free(oldtmpnd);
}
}
??????? return?0;
}
执行程序:
[email protected]:~/memorytest?%?gcc?2.c?-o?mytest
2.c:?In?function?‘main‘:
2.c:37:?warning:?incompatible?implicit?declaration?of?built-in?function?‘strcpy‘
[email protected]:~/memorytest?%?./mytest
id:0,age:20,data:helloworld
id:1,age:21,data:helloworld
id:2,age:22,data:helloworld
delete?id:2
[email protected]:~/memorytest?%?
以上是关于C指针原理(28)-垃圾回收-内存泄露的主要内容,如果未能解决你的问题,请参考以下文章