C指針原理教程之垃圾回收-內(nèi)存泄露
一、內(nèi)存泄露
1、正常的鏈表操作
下面程序建立一個10元素的鏈表,輸出它們的節(jié)點,每個節(jié)點是一個員工的工號和年齡。最后刪除每個節(jié)點,釋放列表。
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 %
下面演示了垃圾的形成,這是內(nèi)存泄露的一種方式,即在鏈表中,某些節(jié)點與鏈表中的其它節(jié)點失去聯(lián)系,導(dǎo)致無法刪除,下面故意讓第4個結(jié)點的next指針指向null,失去與后面6個元素的聯(lián)系。
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);
//下面是形成內(nèi)存泄露第一種情況-垃圾的演示
//生成并輸出鏈表,這個與前面相同
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個鏈表節(jié)點無法刪除,導(dǎo)致后面6個鏈表節(jié)點形成垃圾
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);
//下面是形成內(nèi)存泄露第二種情況-懸掛指針的演示
//生成并輸出鏈表,這個與前面相同
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個節(jié)點,但是讓第6個元素的next指向的地址無效,
//仍指向已經(jīng)刪除的第7個節(jié)點,導(dǎo)致懸掛指針
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;
}
執(zhí)行程序
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函數(shù)表示釋放,這個釋放指的是把這段內(nèi)存標記成可用狀態(tài),或者說,沒有人在用這段內(nèi)存了,也就是意味著如果這段內(nèi)存如果沒有被操作系統(tǒng)重新使用,里面的數(shù)據(jù)還存在,如果被操作系統(tǒng)分配給其它程序或本程序的其它內(nèi)存塊申請之用,則數(shù)據(jù)會被清空。
3、下面是形成內(nèi)存泄露第三種情況-共享的演示,多個指針指向同一個內(nèi)存,這個內(nèi)存因為某個指針不再使用的原因刪除,導(dǎo)致其它指針指向一個無效地址
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(){
//下面是形成內(nèi)存泄露第三種情況-共享的演示,多個指針指向同一個內(nèi)存,這個內(nèi)存因為某個指針不再使用的原因刪除,
//生成并輸出鏈表,生成1個鏈表(共3個元素),元素的data都指向同一個內(nèi)存塊
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);
}
//下面將導(dǎo)致共享的內(nèi)存釋放,但仍有2個結(jié)點指向這個內(nèi)存,這將導(dǎo)致內(nèi)存泄露
//我們故意刪除最后一個節(jié)點,并釋放最后一個結(jié)點的data指針指向的內(nèi)存
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;
}
執(zhí)行程序:
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 %
相關(guān)文章
C語言之關(guān)于二維數(shù)組在函數(shù)中的調(diào)用問題
這篇文章主要介紹了C語言之關(guān)于二維數(shù)組在函數(shù)中的調(diào)用問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07
C++中內(nèi)存池和內(nèi)存分配區(qū)Arena概念詳解
在 C++ 中,內(nèi)存分配區(qū)(Arena)通常指的是預(yù)先分配的一大塊連續(xù)內(nèi)存空間,這種方法的主要目的是提高內(nèi)存分配和釋放的效率,下面就跟隨小編一起了解一下C++中內(nèi)存池和內(nèi)存分配區(qū)Arena相關(guān)概念吧2023-12-12

