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)-垃圾回收-内存泄露的主要内容,如果未能解决你的问题,请参考以下文章

python垃圾回收机制的原理

JavaScript中的垃圾回收机制与内存泄露

jvm内存回收机制

python里面的垃圾回收机制

python里面的垃圾回收机制

Python垃圾回收机制--完美讲解!