WIN32内存管理笔记.net -电脑资料

电脑资料 时间:2019-01-01 我要投稿
【www.unjs.com - 电脑资料】

    内存管理的概念 进程和内存空间 进程:一旦程序正在运行,它就叫进程,进程拥有它自己的内存,文件句柄及其他系统资源.Windows任务栏显示的是主窗口而不是进程,单个进程可能有几个主窗口,每个窗口都由它自己的线程支持. 每个进程都具有它自己"私有"的4GB虚拟地址

   

    内存管理的概念

    进程和内存空间

    进程: 一旦程序正在运行,它就叫进程,进程拥有它自己的内存,文件句柄及其他系统资源. Windows任务栏显示的是主窗口而不是进程,单个进程可能有几个主窗口,每个窗口都由它自己的线程支持.

    每个进程都具有它自己"私有"的4GB虚拟地址空间, 它包括:程序的EXE映像,所加载的任何非系统的DLL(包括MFC DLL),程序的全局数据,内丰映射文件等等.

    Windows95的进程地址空间

    在95中,只有地址空间最底部的2GB(0--0X7FFFFFFF)才是真正私有的,顶部的2GB对于所有的进程都是相同的,被所有的进程共享,它顶部的1GB包括Windows95内核,可执行程序,虚拟设备驱动程序(VxDs)和文件系统代码等,另外1GB存放Windows DLL, 内存映射文件.

    Windows NT进程地址空间

    NT进程只能访问其底部2GB地址空间,且其中最低的和最高的64KB不可访问.NT内核,执行程序及设备程序都驻留在顶部2GB之中.

    虚拟内存的工作方式

    一般分页存储,每一页为4KB,当使用一页时,占用物理内存,但物理地址你永远看不到,Intel微处理器可以有效地把一个32位虚拟地址映射为物理页以及在该页内的偏移量.每个进程都有它自己的分页表,芯片的CR3寄存器就保持指向当前运行的进程的目录页的指针,进程之间的切换只需要更新CR3即可.

    当我们试图访问一个不在当前RAM之中的页,将触发一个中断,Windows通过检查,如果内存引用是假的,就会得到我们常见的"页面错误",程序退出.否则就把该页从磁盘文件读入RAM中.

    内存分配函数

    malloc

    在内存中分配一块指定大小的空间, 返回的类型为void *型, 可以强制转换为其他类型, 如果内存空间已经不足, 则会返回NULL. 注意: 实际分配的空间可能大于指定的大小, 因为内存块还需要保存队列或其他相关的信息.

    free

    释放由malloc,calloc,realloc所分配的内存空间, 如果释放不是由这些函数所分配的内存空间会发生错误.

    new

    为变量初始化内存空间, 例如:

    double *pdoub = new double(20.4);

    delete

    与new对应,释放由new分配的变量所拥有的内存空间.

    HeapAlloc, HeapFree

    GlobalAlloc

    此函数从堆里面分配一个指定大小的内存空间, 此函数仅仅是为了与16位版本兼容而设.

    uFlags: 分配的内存属性, 它可以有以下几种属性值:

    如果此参数为0,缺省为GMEM_FIXED. 它分配一个固定的内存空间, 返回的值为一个指针

    GMEM_MOVEABLE分配一个活动的内存, 在WIN32里,内存块在物理内存里是从不移动的,但它们可以在缺省的堆里面移动. 此参数不能与GMEM_FIXED联合. 它的返回值是一个内存对象句柄,如果要把它转变为一个指针,需使用GlobalLock函数.

    GPTR与GMEM_FIXED和GMEM_ZEROINIT联合

    GHND与GMEM_MOVEABLE和GMEM_ZEROINIT联合

    GMEM_DDESHARE, GMEM_SHARE, 这两个属性首先是为了与16位兼容的,然后使用它可以提高应用程序执行DDE操作的效率,所以如果内存被用于DDE, 可以指定它.

    GMEM_DISCARDABLE, 被忽略,仅是为了与16位兼容.在WIN32里,你必须使用GlobalDiscard函数释放掉一个内存块.它不能与GMEM_FIXED联合.

    GMEM_LOWER,GMEM_NOCOMPACT,GMEM_NODISCARD,GMEM_NOT_BANKED,GMEM_NOTIFY 被忽略,仅为了与16位兼容

    GMEM_ZEROINIT, 将内存块初始化为0.

    dwBytes: 内存块大小

    如果置为0, 且uFlags置为GMEM_MOVEABLE的话, 函数将返回一个内存对话句柄, 此内存对象被标记为已丢弃.

    如果函数调用失败, 将返回NULL, 得到错误信息,调用GetLastError

    释放内存使用GlobalFree函数.

    下面的代码示例使用一块内存:

    HGLOBAL hMem;

    char *pStartBuffer=NULL;

    #define MAX_BUFFER_SIZE 102400

    if ( (hMem = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, MAX_BUFFER_SIZE))==NULL )

    return FALSE;

    pStartBuffer = (char *)GlobalLock(hMem);

    GlobalUnlock(hMem);

    GlobalFree(hMem);

    内存映射文件

    假定程序需要阅读一个DIB文件, 一种方法是分配大小合适的一个缓冲区,打开文件,然后调用一个读函数将整个磁盘文件复制进缓冲区; 还有一种更有效的方法, 就是将一个地址范围直接映射到该文件中即可, 当进程访问一个内存页的时候,Windows将分配RAM并从磁盘中读取数据. 代码如下:

    HANDLE hFile = ::CreateFile(strPathname,GENERIC_READ,

    FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

    ASSERT(hFile!=NULL);

    HANDLE hMap=

    ::CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);

    ASSERT(hMap != NULL);

    LPVOID lpvFile=::MapViewOfFile(hMap,FILE_MAP_READ,0,0,0);//map whole file

    DWORD dwFileSize = ::GetFileSize(hFile,NULL);

    // Use the file

    ::UnmapViewOfFile(lpvFile);

    ::CloseHandle(hMap);

    ::CloseHandle(hFile);

    lpvFile是起始地址,hMap变量包含有文件映射对象的句柄,该对象可以在进程之间共享.

    访问资源

    资源包括在EXE文件和DLL文件里面,因此它们所占用的虚拟地址空间在进程生存期间不发生改变.例如: 需要访问一个位图:

    LPVOID lpvResource=

    (LPVOID)::LoadResource(NULL,::FindResource(NULL,MAKEINTRESOURCE(IDB_REDBLOCKS),RT_BITMAP));

    原文转自:http://www.ltesting.net

最新文章