VC编程精粹需要进行内存的动态分配和释放操作,本文总结常用的VC对内存的操作方法并比较他们之间的区别,以便于读者能够加深对他们的理解并根据项目的实际情况选用适合自己的方案。
用法总结:
1、GlobalAlloc()
The GlobalAlloc function allocates the specified number of bytes from the heap. Windows memory management does not provide a separate local heap and global heap.
Note The global functions are slower than other memory management functions and do not provide as many features. Therefore, new applications should use the heap functions. However, the global functions are still used with DDE, the clipboard functions, and OLE data objects.
GlobalAlloc()主要用于Win32应用程序实现从全局堆中分配出内存供程序使用,是16位WINDOWS程序使用的API,对应于系统的全局栈,返回一个内存句柄,在实际需要使用时,用GlobalLock()来实际得到内存 区。但32位WINDOWS系统中全局栈和局部堆的区别已经不存在了,因此不推荐在Win32中使用该函数,应使用新的内存分配函数HeapAlloc()以得到更好的支持,GlobalAlloc()还可以用,主要是为了 兼容。
函数原型为:
HGLOBAL GlobalAlloc(
UINT uFlags,
SIZE_T dwBytes
);
uFlags参数含义:
GHND GMEM_MOVEABLE和GMEM_ZEROINIT的组合
GMEM_FIXED 分配固定内存,返回值是一个指针
GMEM_MOVEABLE 分配活动内存,在Win32中,内存块不能在物理内存中移动,但能在默认的堆中移动。返回值是内存对象的句柄,用函数GlobalLock可将句柄转化为指针
GMEM_ZEROINIT 将内存内容初始化为零
GPTR GMEM_FIXED和GMEM_ZEROINIT的组合
一般情况下我们在编程的时候,给应用程序分配的内存都是可以移动的或者是可以丢弃的,这样能使有限的内存资源充分利用,所以,在某一个时候我们分配的那块 内存的地址是不确定的,因为他是可以移动的,所以得先锁定那块内存块,这儿应用程序需要调用API函数GlobalLock函数来锁定句柄。如下: lpMem=GlobalLock(hMem); 这样应用程序才能存取这块内存。所以我们在使用GlobalAllock时,通常搭配使用GlobalLock,当然在不使用内存时,一定记得使用 GlobalUnlock,否则被锁定的内存块一直不能被其他变量使用。
GlobalAlloc对应的释放空间的函数为GlobalFree。
GlobalAlloc是win16留下来的函数,它调用HeapAlloc分配堆中的内存。在理想的win32环境下,我们不需要 GlobalAlloc,但是实际上,我们还得保留从win16移植过来的许多代码。在这些代码中使用了“内存句柄”(HGLOBAL)参数而不是32位 的内存地址。
GlobalAlloc根据其属性参数做两件不同的事情。如果参数指定了GMEM_FIXED,则GlobalAlloc简单调用HeapAlloc,把 返回地址作为一个32位HGLOBAL值;如果参数指定了GMEM_MOVEABLE,则返回的HGLOBAL值是一个指向进程里句柄表中某一项入口的指 针,该入口包含指向实际HeapAlloc分配的内存的指针。
从本质上,如果我们不调用GlobalReAlloc函数,我们就可以用HeapAlloc代替GlobalAlloc。
2、HeapAlloc()
The HeapAlloc function allocates a block of memory from a heap.The allocated memory is not movable.
MSDN上的解释为:HeapALloc是从堆上分配一块内存,且分配的内存是不可移动的(即如果没有连续的空间能满足分配的大小,程序不能将其他零散的 空间利用起来,从而导致分配失败),该分配方法是从一指定地址开始分配,而不像GloabalAlloc是从全局堆上分配,这个有可能是全局,也有可能是 局部。函数原型为:
LPVOID
HeapAlloc(
HANDLE hHeap,
DWORD dwFlags,
SIZE_T dwBytes
);
hHeap是进程堆内存开始位置。
dwFlags是分配堆内存的标志。包括HEAP_ZERO_MEMORY,即使分配的空间清零。
dwBytes是分配堆内存的大小。
其对应的释放空间函数为HeapFree。
使用HeapAlloc分配的内存有两点和GlobalAlloc不同:
1)、不可以移动,所以可能会产生内存碎片
2)、可以提供串行化访问功能,多线程时不用自己再同步了
3、malloc()
malloc()是C运行库中的动态内存分配函数,主要用于ANSI C程序中,是标准库函数。WINDOWS程序基本不再使用这种方法进行内存操作,因为它比WINDOWS内存分配函数少了一些特性,如整理内存。
原型:extern void *malloc(unsigned int num_bytes);
头文件:#include <memory.h>
功能:分配长度为num_bytes字节的内存块
说明:如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。
举例:
// malloc.c
#include <memory.h>
#include <stdio.h>
main()
{
char *p;
clrscr(); // clear screen
p=(char *)malloc(100);
if(p)
printf("Memory Allocated at: %x",p);
else
printf("Not Enough Memory!\n");
free(p);
getchar();
return 0;
}
4、new
标准C++一般使用new语句分配动态的内存空间,需要申请数组时,可以直接使用new int[3]这样的方式,释放该方法申请的内存空间使用对应的delete语句,需要释放的内存空间为一个数组,则使用delete [] ary;这样的方式。
要访问new所开辟的结构体空间,无法直接通过变量名进行,只能通过赋值的指针进行访问.
new在内部调用malloc来分配内存,delete在内部调用free来释放内存。
举例:
#include
#include
using namespace std;
int main() {
int *a = new int[34];
int *b = new int[];
int (*c)[2] = new int[34][2];
int (*d)[2] = new int[][2];
int (*e)[2][3] = new int[34][2][3];
int (*f)[2][3] = new int[][2][3];
a[0] = 1;
b[0] = 1; //运行时错误,无分配的内存,b只起指针的作用,用来指向相应的数据
c[0][0] = 1;
d[0][0] = 1; //运行时错误,无分配的内存,d只起指针的作用,用来指向相应的数据
e[0][0][0] = 1;
f[0][0][0] = 1; //运行时错误,无分配的内存,f只起指针的作用,用来指向相应的数据
cout<< cout<< cout<< cout<< cout<< cout<< delete[] a; delete[] b; delete[] c;
delete[] d; delete[] e; delete[] f;
}
它们之间的区别主要有以下几点:
1、GlobalAlloc()函数在程序的堆中分配一定的内存,是Win16的函数,对应于系统的全局栈,而在Win32中全局栈和局部堆的区别已经不存在了,因此不推荐在Win32中使用该函数。
2、malloc()是标准库函数,而new则是运算符,它们都可以用于申请动态内存。
3、new()实际上调用的是malloc()函数。
4、new运算符除了分配内存,还可以调用构造函数,但是malloc()函数只负责分配内存。
5、对于非内部数据类型的对象而言,只使用malloc()函数将无法满足动态对象的要求,因为malloc()函数不能完成执行构造函数的任务。
6、malloc(); 和 HeapAlloc(); 都是从堆中分配相应的内存,不同的是一个是c run time的函数,一个是windows系统的函数, 对于windows程序来说,使用HeapAlloc();会比malloc();效率稍稍高一些。