free与内存分配的一些想法

superdinosaur520 2007-11-20 04:20:39
释放指针p所指向的内存时,我们常常使用:
free(p);
p=NULL;
但如果程序改为这样,又会是什么结果呢:
int* p = (int*)malloc(sizeof(int)*100); //400
p++;
free(p);
p=NULL;
...
这时编译器还能知道要释放多大的空间吗?

在网上搜索了很久,终于找到一篇文章:
http://topic.csdn.net/t/20050120/12/3740527.html
通过此文可以知道,在malloc开辟内存时,系统会多开辟一块内存区域存放一些内存大小等信息,而free正是通过这些额外的信息来释放内存的,由于p++后free已经找不到这些额外的信息了,所以会出现错误或内存泄露。

那么,这些额外的信息是存放在哪里的呢?紧挨着p指向的首地址后面,或存储在“符号表”里?
问题1,如果存储在紧挨着p指向的首地址后面,那么p++就不是指向数组的下一个元素了(这里假设p指向数组)。
问题2,既然有这些额外的信息,那么怎么计算这块内存的大小呢?用sizeof(p)的结果是4而不是400哦~~

另外,如果有一个这样的函数:
char * conv(char* ap)
{char * t;
t=(char*)malloc(100);
if (t==NULL) exit(1);
//...
return t;}
那么这里创建的100个字节的空间该如何释放呢?在调用该函数的代码后面再调用free?
...全文
182 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
xxmv99 2007-11-26
  • 打赏
  • 举报
回复

我来拜见 11 楼的

pptor 2007-11-26
  • 打赏
  • 举报
回复
学习下
License2Kill 2007-11-26
  • 打赏
  • 举报
回复
新手区都是高手啊,学习中。这个很接近底层了。
superdinosaur520 2007-11-23
  • 打赏
  • 举报
回复
大家有写过求指针指向的空间的大小的函数吗?
suyouxin 2007-11-21
  • 打赏
  • 举报
回复
TO 11楼

3楼只是给你举了个例,你本身使用的malloc并不一定是那样实现的
那个只是给你说了下原理,实际运用中的堆管理比那复杂得多
wh_peng 2007-11-21
  • 打赏
  • 举报
回复
很好
wKernel 2007-11-21
  • 打赏
  • 举报
回复
jf
superdinosaur520 2007-11-21
  • 打赏
  • 举报
回复
既然free可以判断需要释放的空间的大小,那么就应该可以写出一个函数计算指针所指向的空间的大小。
但sizeof(p)==4(或2),不知道有没有写过这个函数的(计算指向的空间(如数组等)的大小)
NET小工 2007-11-21
  • 打赏
  • 举报
回复
大哥你真邪门,练的是辟邪剑谱还是葵花宝典。

11楼那个程序,怎一个邪字了得,你返回结构体成员size的值,你那个size,在哪里赋过值?这东西当然是个随机数,八成是个天文级的负数。

还有,按照malloc分配内存的逻辑,额服了。。。。。。malloc有这样的逻辑吗?你能保证*p位于栈顶?典型的内存空间损坏,如果程序中断,你就该谢天谢地了。

最后,我看了半天,没看出你那个mcb跟p指向的空间大小有嘛关系,mcb跟p纯属邻居关系,而且mcb十之八九是非法侵入民宅的货,二者如有关联,纯属YY.
superdinosaur520 2007-11-20
  • 打赏
  • 举报
回复
按照malloc分配内存的逻辑,写了下面的函数计算指针指向的空间的大小,但计算结果总是负数,不知何故,请帮我查查看

struct mem_control_block {
int is_available;
int size;
};

//计算指针指向的空间的大小
int sizeof_p(char *p)
{
if (p==NULL ) return 0;
struct mem_control_block *mcb;
mcb = (struct mem_control_block *)(p - sizeof(struct mem_control_block));
return mcb->size;
}

ofourme 2007-11-20
  • 打赏
  • 举报
回复
我写过一个模拟内存分配的函数,
后来同TC的内存分配函数比较,分析其返回的地址,发觉两者有异曲同工之妙。
可能实现机制是一样的吧。我把我的程序给你看吧。
欢迎到我的主页看看:http://hi.baidu.com/breezyvalley
PS:请问怎样弄成C/C++源码格式的?

模拟内存分配2007-05-18 17:06
/**********
1.memory.h
**********/

#ifndef MEMORY_H
#define MEMORY_H

#include<iostream.h>
#include<iomanip.h>

////////////////////////////////////////////////////////////////////////////

typedef int INT;
#define RAM(x) (*((INT*)(node+(x))))

class CRam
{
private:
char *node;
INT head; //可分配空间起始位置
unsigned int spaceSize;

public:
CRam(unsigned int maxSpaceSize=100);
~CRam(){delete []node;}
void* ApplyRam(int size);
int FreeSpace(void* &p);
void Infor();
};

////////////////////////////////////////

CRam::CRam(unsigned int maxSpaceSize)
{
INT t;

spaceSize=maxSpaceSize+2*sizeof(INT); //实际申请空间为spaceSize
node=new char[spaceSize];
if(node==NULL)
{
cerr<<"\n >>>无法申请到足够的内存"<<endl;
return;
}
head=0; //晕,忘记给head赋值了,难怪老是错误。
t=RAM(0)=spaceSize-sizeof(INT);
RAM(t)=0; //正数t表示有t个可用空间,负数表示空间不能使用,0表示已达末尾
}

///////////////////////////////////////

void* CRam::ApplyRam(int size)
{
INT t=head,h=head;
INT t2;

if(size<0) {cerr<<"\n >>>内存大小不能为负"<<endl; return NULL;}
while( RAM(t) )
{ if( RAM(t) >0)
{ t2=RAM(t);
while( RAM(t2) >0 ) t2=RAM(t2); //合并连续的可用空间
RAM(t)=t2;
if( int(RAM(t)-t-sizeof(INT))>=size )//没有int()居然就变成unsigned
{ if( int(RAM(t)-t-2*sizeof(INT))>size )
{ head=t+size+sizeof(INT);
t2=RAM(t); RAM(t)=-head;
RAM(head)=t2;
}
else {head=RAM(t); RAM(t)*=-1;}
if(t!=h) head=h;
return (void*)(node+t+sizeof(INT));
}
t=RAM(t);
}
else t=-RAM(t);
}
cerr<<"\n >>>内存不足"<<endl;
return NULL;
}

///////////////////////////////////////

int CRam::FreeSpace( void* &p)
{
INT t2,t=(char*)p-node-sizeof(INT);

#ifdef TEST
cout<<"node: "<<(void*)node<<endl;
cout<<"p : "<<p<<endl;
cout<<"pos : "<<t<<endl;
getchar();
#endif

if(t<0 || t>=int(spaceSize-sizeof(INT)) || RAM(t)>0 )
{
cerr<<"\n >>>释放空间错误"<<endl;
return 0;
}
if(t<head) head=t;
t2=RAM(t)*-1;
while( RAM(t2)>0 ) t2=RAM(t2);
RAM(t)=t2;
p=NULL;
return 1;
}

///////////////////////////////////////

void CRam::Infor()
{
INT t=0,t2;
int numofp=0,allm=0,freem=0,size,nuse=1;

cout<<"__________________________________________________________\n"<<endl;

while(RAM(t))
{ numofp++;
cout<<"内存段\t"<<setw(4)<<numofp<<"("<<setw(3)<<t<<") 长度:";
if(RAM(t)<0) {t2=-RAM(t); nuse=0;}
else {t2=RAM(t); nuse=1;}
size=t2-t-sizeof(INT);
if(nuse) freem+=size;
allm+=size;
cout<<setw(5)<<size<<" bytes. ";
if(nuse) cout<<" 可用"<<endl;
else cout<<"不可用"<<endl;
t=t2;
}
cout<<endl<<"内存分段数: "<<numofp<<" 有效空间: ";
cout<<allm<<" 可用空间: "<<freem<<endl<<endl;
}

////////////////////////////////////////////////////////////////////////////

#endif



/*************
2主函數
*************/

#include<iostream.h>
#include"stdio.h"
#include"memory.h"

#define N 100

void f2()
{
int i,j;
CRam ram(N);
void* arr[N]={0};

ram.Infor();
cout<<"\n输入要申请的空间大小(0删除, -1 退出):";
cin>>i;
while(i>=0)
{ if(i==0)
{ while(1)
{ cout<<"\n输入要释放的空间位置( -1 返回):";
cin>>i;
if(i<0) break;
if(i>=N) {cout<<"超出范围"<<endl; continue;}
ram.FreeSpace(arr[i]);
if(!arr[i])
{ j=i+1;
while(arr[j]) j++;
arr[i]=arr[j-1];
arr[j-1]=0;
ram.Infor();
}
}
}
else
{ j=0;
while(arr[j]) j++;
arr[j]=ram.ApplyRam(i);
}
ram.Infor();

cout<<"\n输入要申请的空间大小(0删除, -1 退出):";
cin>>i;
}
}

int main()
{
f2();
return 0;
}
ofourme 2007-11-20
  • 打赏
  • 举报
回复
我写过一个模拟内存分配的函数,
后来同TC的内存分配函数比较,分析其返回的地址,发觉两者有异曲同工之妙。
可能实现机制是一样的吧。我把我的程序给你看吧。
欢迎到我的主页看看:http://hi.baidu.com/breezyvalley
PS:请问怎样弄成C/C++源码格式的?

模拟内存分配2007-05-18 17:06

/**********
1.memory.h
**********/

#ifndef MEMORY_H
#define MEMORY_H

#include<iostream.h>
#include<iomanip.h>

////////////////////////////////////////////////////////////////////////////

typedef int INT;
#define RAM(x) (*((INT*)(node+(x))))

class CRam
{
private:
char *node;
INT head; //可分配空间起始位置
unsigned int spaceSize;

public:
CRam(unsigned int maxSpaceSize=100);
~CRam(){delete []node;}
void* ApplyRam(int size);
int FreeSpace(void* &p);
void Infor();
};

////////////////////////////////////////

CRam::CRam(unsigned int maxSpaceSize)
{
INT t;

spaceSize=maxSpaceSize+2*sizeof(INT); //实际申请空间为spaceSize
node=new char[spaceSize];
if(node==NULL)
{
cerr<<"\n >>>无法申请到足够的内存"<<endl;
return;
}
head=0; //晕,忘记给head赋值了,难怪老是错误。
t=RAM(0)=spaceSize-sizeof(INT);
RAM(t)=0; //正数t表示有t个可用空间,负数表示空间不能使用,0表示已达末尾
}

///////////////////////////////////////

void* CRam::ApplyRam(int size)
{
INT t=head,h=head;
INT t2;

if(size<0) {cerr<<"\n >>>内存大小不能为负"<<endl; return NULL;}
while( RAM(t) )
{ if( RAM(t) >0)
{ t2=RAM(t);
while( RAM(t2) >0 ) t2=RAM(t2); //合并连续的可用空间
RAM(t)=t2;
if( int(RAM(t)-t-sizeof(INT))>=size )//没有int()居然就变成unsigned
{ if( int(RAM(t)-t-2*sizeof(INT))>size )
{ head=t+size+sizeof(INT);
t2=RAM(t); RAM(t)=-head;
RAM(head)=t2;
}
else {head=RAM(t); RAM(t)*=-1;}
if(t!=h) head=h;
return (void*)(node+t+sizeof(INT));
}
t=RAM(t);
}
else t=-RAM(t);
}
cerr<<"\n >>>内存不足"<<endl;
return NULL;
}

///////////////////////////////////////

int CRam::FreeSpace( void* &p)
{
INT t2,t=(char*)p-node-sizeof(INT);

#ifdef TEST
cout<<"node: "<<(void*)node<<endl;
cout<<"p : "<<p<<endl;
cout<<"pos : "<<t<<endl;
getchar();
#endif

if(t<0 || t>=int(spaceSize-sizeof(INT)) || RAM(t)>0 )
{
cerr<<"\n >>>释放空间错误"<<endl;
return 0;
}
if(t<head) head=t;
t2=RAM(t)*-1;
while( RAM(t2)>0 ) t2=RAM(t2);
RAM(t)=t2;
p=NULL;
return 1;
}

///////////////////////////////////////

void CRam::Infor()
{
INT t=0,t2;
int numofp=0,allm=0,freem=0,size,nuse=1;

cout<<"__________________________________________________________\n"<<endl;

while(RAM(t))
{ numofp++;
cout<<"内存段\t"<<setw(4)<<numofp<<"("<<setw(3)<<t<<") 长度:";
if(RAM(t)<0) {t2=-RAM(t); nuse=0;}
else {t2=RAM(t); nuse=1;}
size=t2-t-sizeof(INT);
if(nuse) freem+=size;
allm+=size;
cout<<setw(5)<<size<<" bytes. ";
if(nuse) cout<<" 可用"<<endl;
else cout<<"不可用"<<endl;
t=t2;
}
cout<<endl<<"内存分段数: "<<numofp<<" 有效空间: ";
cout<<allm<<" 可用空间: "<<freem<<endl<<endl;
}

////////////////////////////////////////////////////////////////////////////

#endif



/*************
2主函數
*************/

#include<iostream.h>
#include"stdio.h"
#include"memory.h"

#define N 100

void f2()
{
int i,j;
CRam ram(N);
void* arr[N]={0};

ram.Infor();
cout<<"\n输入要申请的空间大小(0删除, -1 退出):";
cin>>i;
while(i>=0)
{ if(i==0)
{ while(1)
{ cout<<"\n输入要释放的空间位置( -1 返回):";
cin>>i;
if(i<0) break;
if(i>=N) {cout<<"超出范围"<<endl; continue;}
ram.FreeSpace(arr[i]);
if(!arr[i])
{ j=i+1;
while(arr[j]) j++;
arr[i]=arr[j-1];
arr[j-1]=0;
ram.Infor();
}
}
}
else
{ j=0;
while(arr[j]) j++;
arr[j]=ram.ApplyRam(i);
}
ram.Infor();

cout<<"\n输入要申请的空间大小(0删除, -1 退出):";
cin>>i;
}
}

int main()
{
f2();
return 0;
}
superdinosaur520 2007-11-20
  • 打赏
  • 举报
回复
创建数组:
char a[100];
的时候是不是系统自动调用了a=(char[])malloc(sizeof(char)*100);呢?
如果这样,是不是可以写一个统一的函数,计算指针指向的空间的大小(根据上文中的mem_control_block)?
因为sizeof(指针p)时等于4,用起来不很方便。
suyouxin 2007-11-20
  • 打赏
  • 举报
回复
malloc free 的机制很多,上面只是其中一种。

参见这文章
http://www.ibm.com/developerworks/cn/linux/l-memory/
sukyin 2007-11-20
  • 打赏
  • 举报
回复
gcc编译
sukyin 2007-11-20
  • 打赏
  • 举报
回复

#include <stdio.h>
#include <string.h>

int main( void )
{
int* p = (int*)malloc(sizeof(int)*10); //400
p+=5;
free(p);
p=NULL;
printf("mei beng a!");
getch();
}


貌似没崩。
superdinosaur520 2007-11-20
  • 打赏
  • 举报
回复
感谢幽明天竹如此详细的解答,问题终于解决了
神速!
xugang_2001 2007-11-20
  • 打赏
  • 举报
回复
上面排版有点问题:

三、malloc()以及free()的机制:

这个部分我今天才有了新的认识!而且是转折性的认识!所以,
这部分可能会有更多一些认识上的错误!不对的地方请大家帮忙指出!

事实上,仔细看一下free()的函数原型,也许也会发现似乎很神奇,free()函数非常简单,
只有一个参数,只要把指向申请空间的指针传递

给free()中的参数就可以完成释放工作!这里要追踪到malloc()的申请问题了。
申请的时候实际上占用的内存要比申请的大。因为超出的空间是用来记录对这块内存的管理信息。
先看一下在《UNIX环境高级编程》中第七章的一段话:

大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息——分配块的长度,指向下一个分配块的指针等等。
这就意味着如果写过一个已分配区的尾端,则会改写后一块的管理信息。这种类型的错误是灾难性的,
但是因为这种错误不会很快就暴露出来,所以也就很难发现。将指向分配块的指针向后移动也可能会改写本块的管理信息。

以上这段话已经给了我们一些信息了。malloc()申请的空间实际我觉得就是分了两个不同性质的空间。
一个就是用来记录管理信息的空间,另外一个就是可用空间了。而用来记录管理信息的实际上是一个结构体。
在C语言中,用结构体来记录同一个对象的不同信息是

天经地义的事!下面看看这个结构体的原型:
程序代码:
struct mem_control_block {
int is_available; //这是一个标记?
int size; //这是实际空间的大小
};



对于size,这个是实际空间大小。这里其实我有个疑问,is_available是否是一个标记?
因为我看了free()的源代码之后对这个变量感觉有点纳闷(源代码在下面分析)。这里还请大家指出!

所以,free()就是根据这个结构体的信息来释放malloc()申请的空间!而结构体的两个成员的大小我想应该是操作系统的事了。
但是这里有一个问题,malloc()申请空间后返回一个指针应该是指向第二种空间,也就是可用空间!
不然,如果指向管理信息空间的话,写入的内容和结构体的类型有可能不一致,或者会把管理信息屏蔽掉,
那就没法释放内存空间了,所以会发生错误!(感觉自己这里说的是废话)

好了!下面看看free()的源代码,我自己分析了一下,觉得比起malloc()的源代码倒是容易简单很多。只是有个疑问,下面指出!
程序代码:
// code...

void free(void *ptr)
{
struct mem_control_block *free;
free = ptr - sizeof(struct mem_control_block);
free->is_available = 1;
return;
}

看一下函数第二句,这句非常重要和关键。其实这句就是把指向可用空间的指针倒回去,
让它指向管理信息的那块空间,因为这里是在值上减去了一个结构体的大小!后面那一句free->is_available = 1;
我有点纳闷!我的想法是:这里is_available应该只是一个标记而已!因为从这个变量的名称上来看,
is_available 翻译过来就是“是可以用”。不要说我土!我觉得变量名字可以反映一个变量的作用,特别是严谨的代码。
这是源代码,所以我觉得绝对是严谨的!!这个变量的值是1,表明是可以用的空间!只是这里我想了想,
如果把它改为0或者是其他值不知道会发生什么事?!但是有一点我可以肯定,就是释放绝对不会那么顺利进行!因为这是一个标记!

当然,这里可能还是有人会有疑问,为什么这样就可以释放呢??我刚才也有这个疑问。后来我想到,
释放是操作系统的事,那么就free()这个源代码来看,什么也没有释放,对吧?但是它确实是确定了管理信息的那块内存的内容。
所以,free()只是记录了一些信息,然后告诉操作系统那块内存可以去释放,具体怎么告诉操作系统的我不清楚,
但我觉得这个已经超出了我这篇文章的讨论范围了。

那么,我之前有个错误的认识,就是认为指向那块内存的指针不管移到那块内存中的哪个位置都可以释放那块内存!
但是,这是大错特错!释放是不可以释放一部分的!首先这点应该要明白。而且,从free()的源代码看,
ptr只能指向可用空间的首地址,不然,减去结构体大小之后一定不是指向管理信息空间的首地址。
所以,要确保指针指向可用空间的首地址!不信吗?自己可以写一个程序然后移动指向可用空间的指针,看程序会有会崩!
xugang_2001 2007-11-20
  • 打赏
  • 举报
回复
三、malloc()以及free()的机制:

这个部分我今天才有了新的认识!而且是转折性的认识!所以,这部分可能会有更多一些认识上的错误!不对的地方请大家帮忙指出!

事实上,仔细看一下free()的函数原型,也许也会发现似乎很神奇,free()函数非常简单,只有一个参数,只要把指向申请空间的指针传递

给free()中的参数就可以完成释放工作!这里要追踪到malloc()的申请问题了。申请的时候实际上占用的内存要比申请的大。因为超出的空间是用来记录对这块内存的管理信息。先看一下在《UNIX环境高级编程》中第七章的一段话:

大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息——分配块的长度,指向下一个分配块的指针等等。这就意味着如果写过一个已分配区的尾端,则会改写后一块的管理信息。这种类型的错误是灾难性的,但是因为这种错误不会很快就暴露出来,所以也就很难发现。将指向分配块的指针向后移动也可能会改写本块的管理信息。

以上这段话已经给了我们一些信息了。malloc()申请的空间实际我觉得就是分了两个不同性质的空间。一个就是用来记录管理信息的空间,另外一个就是可用空间了。而用来记录管理信息的实际上是一个结构体。在C语言中,用结构体来记录同一个对象的不同信息是

天经地义的事!下面看看这个结构体的原型:
程序代码:
struct mem_control_block {
int is_available; //这是一个标记?
int size; //这是实际空间的大小
};



对于size,这个是实际空间大小。这里其实我有个疑问,is_available是否是一个标记?因为我看了free()的源代码之后对这个变量感觉有点纳闷(源代码在下面分析)。这里还请大家指出!

所以,free()就是根据这个结构体的信息来释放malloc()申请的空间!而结构体的两个成员的大小我想应该是操作系统的事了。但是这里有一个问题,malloc()申请空间后返回一个指针应该是指向第二种空间,也就是可用空间!不然,如果指向管理信息空间的话,写入的内容和结构体的类型有可能不一致,或者会把管理信息屏蔽掉,那就没法释放内存空间了,所以会发生错误!(感觉自己这里说的是废话)

好了!下面看看free()的源代码,我自己分析了一下,觉得比起malloc()的源代码倒是容易简单很多。只是有个疑问,下面指出!
程序代码:
// code...

void free(void *ptr)
{
struct mem_control_block *free;
free = ptr - sizeof(struct mem_control_block);
free->is_available = 1;
return;
}

看一下函数第二句,这句非常重要和关键。其实这句就是把指向可用空间的指针倒回去,让它指向管理信息的那块空间,因为这里是在值上减去了一个结构体的大小!后面那一句free->is_available = 1;我有点纳闷!我的想法是:这里is_available应该只是一个标记而已!因为从这个变量的名称上来看,is_available 翻译过来就是“是可以用”。不要说我土!我觉得变量名字可以反映一个变量的作用,特别是严谨的代码。这是源代码,所以我觉得绝对是严谨的!!这个变量的值是1,表明是可以用的空间!只是这里我想了想,如果把它改为0或者是其他值不知道会发生什么事?!但是有一点我可以肯定,就是释放绝对不会那么顺利进行!因为这是一个标记!

当然,这里可能还是有人会有疑问,为什么这样就可以释放呢??我刚才也有这个疑问。后来我想到,释放是操作系统的事,那么就free()这个源代码来看,什么也没有释放,对吧?但是它确实是确定了管理信息的那块内存的内容。所以,free()只是记录了一些信息,然后告诉操作系统那块内存可以去释放,具体怎么告诉操作系统的我不清楚,但我觉得这个已经超出了我这篇文章的讨论范围了。

那么,我之前有个错误的认识,就是认为指向那块内存的指针不管移到那块内存中的哪个位置都可以释放那块内存!但是,这是大错特错!释放是不可以释放一部分的!首先这点应该要明白。而且,从free()的源代码看,ptr只能指向可用空间的首地址,不然,减去结构体大小之后一定不是指向管理信息空间的首地址。所以,要确保指针指向可用空间的首地址!不信吗?自己可以写一个程序然后移动指向可用空间的指针,看程序会有会崩!
yyy6210 2007-11-20
  • 打赏
  • 举报
回复
等待学习~~~

一般来说好像最好同一级别申请和释放~~

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧