malloc 与 free
luyued 发布于 2011-01-13 02:01 浏览 N 次malloc/free
malloc/free是C和C++语言的标准库函数, 可以被覆盖, 需要头文件库函数支持,
不在编译器控制范围之内, 不能够执行构造函数和析构函数的任务
malloc标准库函数的作用:分配动态堆内存
free标准库函数的作用:释放动态堆内存
用malloc分配的一块内存, 你要用指针访问并且要通过移动指针来访问内存数据
malloc只认字节数, 不管数据类型, 只能返回一个void*, 程序员要把void*强制类型转换成相应的指针类型,
同时还要用 if (NULL != ...) 来判断申请内存空间是否成功
new/delete
new/delete是C++的操作符, 是保留字, 可以被重载, 不需要头文件支持,
在编译器控制范围之内, 能够执行构造函数和析构函数的任务
new操作符的作用:分配动态堆内存、初始化对象(调用构造函数)
delete操作符的作用:清理对象(调用析构函数)、释放动态堆内存
用new创建的对象, 你可以用成员函数访问, 不用直接访问它的地址空间。
new可以认为是malloc加构造函数的执行, new出来的指针是直接带类型信息的, 不用进行强制类型转换
malloc/free 和 new/delete 的联系与区别
对于基本数据类型来说, 由于不像“对象”那样有构造与析构的过程,所以对它们而言,
malloc/free 和 new/delete是等价的
既然new/delete的功能完全覆盖了malloc/free, 为什么C++不把malloc/free淘汰出局呢?
因为C++程序经常要调用C函数, 而C程序只能用malloc/free分配和释放动态堆内存
内存泄漏对于malloc或者new都可以检查出来的, 区别在于new可以指明是那个文件的那一行, 而malloc没有这些信息
如果用free释放“new创建的动态对象”, 那么该对象因无法执行析构函数而可能导致程序出错。
如果用delete释放“malloc申请的动态内存”, 理论上讲程序不会出错, 但是该程序的可读性很差。
所以new/delete必须配对使用, malloc/free也一样。
Visual C++ 6.0中的malloc/free 和 new/delete
int* p = (int*)malloc(5 * sizeof(int));
void* __cdecl malloc(size_t nSize)
{
void* res = _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0);
return res;
}
void* __cdecl _nh_malloc_dbg(size_t nSize, int nhFlag, int nBlockUse, const char * szFileName, int nLine)
{
void* pvBlk;
for (;;)
{
_mlock(_HEAP_LOCK);
__try
{
pvBlk = _heap_alloc_dbg(nSize, nBlockUse, szFileName, nLine);
}
__finally
{
_munlock(_HEAP_LOCK);
}
if (pvBlk || nhFlag == 0)
return pvBlk;
}
}
void* __cdecl _heap_alloc_dbg(size_t nSize, int nBlockUse, const char * szFileName, int nLine)
{
pHead = (_CrtMemBlockHeader*)_heap_alloc_base(blockSize);
// 在你分配的内存后面加4个256(即: 4个FD), 在释放内存时, 会以这4个FD作为内存界限的标志
// _bNoMansLandFill的值是253, nNoMansLandSize的值是4
memset((void*)pHead->gap, _bNoMansLandFill, nNoMansLandSize);
memset((void*)(pbData(pHead) + nSize), _bNoMansLandFill, nNoMansLandSize);
memset((void*)pbData(pHead), _bCleanLandFill, nSize);
return (void*)pbData(pHead);
}
void* __cdecl _heap_alloc_base(size_t size)
{
return HeapAlloc(_crtheap, 0, size); // HeapAlloc函数是微软内部API, 用于分配堆内存
}
free(p);
void __cdecl free(void * pUserData)
{
_free_dbg(pUserData, _NORMAL_BLOCK);
}
void __cdecl _free_dbg(void* pUserData, int nBlockUse)
{
_ASSERTE(_CrtIsValidHeapPointer(pUserData));
// _bNoMansLandFill的值是253, nNoMansLandSize的值是4
CheckBytes(pHead->gap, _bNoMansLandFill, nNoMansLandSize);
CheckBytes(pbData(pHead) + pHead->nDataSize, _bNoMansLandFill, nNoMansLandSize);
memset(pHead, _bDeadLandFill, sizeof(_CrtMemBlockHeader) + pHead->nDataSize + nNoMansLandSize);
_free_base(pHead);
}
int __cdecl _CrtIsValidHeapPointer(const void* pUserData)
{
return HeapValidate(_crtheap, 0, pHdr(pUserData)); // HeapValidate函数是微软内部API, 用于验证指定堆的有效性
}
static int __cdecl CheckBytes(unsigned char* pb, unsigned char bCheck, size_t nSize) // bCheck的值是253, nSize的值是4
{
int bOkay = TRUE;
while (nSize--)
{
if (*pb++ != bCheck) // 检查你分配的内存后面是否有4个256(即: 4个FD), 如果没有, 就说明有错误
bOkay = FALSE;
}
return bOkay; // 检查无误, 返回TRUE
}
void __cdecl _free_base(void* pBlock)
{
PHEADER pHeader;
if (pBlock == NULL)
return;
HeapFree(_crtheap, 0, pBlock); // 释放一个内存块, 这个内存块是用HeapAlloc或HeapReAlloc分配的
}
int* a = new int[6];
void* operator new(unsigned int cb)
{
void* res = _nh_malloc(cb, 1);
return res;
}
void* __cdecl _nh_malloc(size_t nSize, int nhFlag)
{
return _nh_malloc_dbg(nSize, nhFlag, _NORMAL_BLOCK, NULL, 0);
}
delete a;
void operator delete(void* pUserData)
{
_CrtMemBlockHeader * pHead;
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK);
pHead = pHdr(pUserData);
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg(pUserData, pHead->nBlockUse);
_munlock(_HEAP_LOCK);
}
class Person
{
public:
Person() { a = 1; b = 2.0; c = 'f'; }
int GetA() { return a; }
double GetB() { return b; }
char GetC() { return c; }
private:
int a;
double b;
char c;
};
int main()
{
Person* p = new Person();
delete p;
return 0;
}
Person* p = new Person();这句代码先调用
void* operator new(unsigned int cb)
{
void* res = _nh_malloc(cb, 1);
return res;
}
后调用Person() { a = 1; b = 2.0; c = 'f'; }
delete p;这句代码调用
void operator delete(void* pUserData)
{
_CrtMemBlockHeader * pHead;
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK);
pHead = pHdr(pUserData);
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg(pUserData, pHead->nBlockUse);
_munlock(_HEAP_LOCK);
}
int main()
{
char* p = new char;
cin >> p;
cout << p;
delete p;
return 0;
}
Debug调试程序:
char* p = new char; 这句代码使p的内容变成0x00382DE0
00382DE0 CD FD FD FD FD
分析: CD是帮char占一个字节的位置, 4个FD作为内存界限的标志
cin >> p; 这句代码调用 istream& istream::operator>>(char* s)
如果你输入a[Enter], 则内存如下:
00382DE0 61 00 FD FD FD
分析: Ox61是字符'a'的ASCII码, 0x00是operator>>加的'\0', 因为char* s是字符串, 要以'\0'结尾, p是实参, s是形参
cout << p; 这句代码调用 ostream& ostream::operator<<(const char* s)
执行完这句代码后, 屏幕并没有输出任何信息
delete p; 这句代码调用 void operator delete(void* pUserData)
在void __cdecl _free_dbg(void* pUserData, int nBlockUse)的第二个CheckBytes代码里面出现问题Debug Error,
选择“忽略”错误, 最终屏幕还是没有输出任何信息
Debug直接执行程序:
如果你输入a[Enter], 则会出现问题Debug Error
Release直接执行程序:
如果你输入a[Enter], 则会很好地输出a
如果你输入abcdefghijk[Enter], 则会很好地输出abcdefghijk
- 06-30· 引用 (原创)陌上花.赏菊
- 06-21· “感动南京”人物谢二喜
- 06-21· 男士服饰搭配的基本原则
- 06-21· 程式内衣简介
- 06-21· 搭配点评 无论你身材、肤
- 06-21· 品牌内衣
- 06-21· 红脸蛋与绿西瓜
- 06-19· [神马]【2011-03-03】外贸童
- 06-19· 济南小商品 济南大明湖东
- 06-19· 妒
- 06-19· 2011年03月24日
- 06-19· 一个小小的纹身
- 06-19· 女装,女鞋,超值店
- 06-19· 谈谈购房体会
- 06-19· [转载]中医肾病用药体会
- 06-19· 我的读书心得体会
- 06-19· [转载]学习精细化管理写了
- 06-19· 谈谈拜《楞严经》的体会
- 06-18· 上海基本药物增补高价外
- 06-18· 辉瑞与百时美施贵宝叫停