Win32內存管理



                                                                        


  2 地址空間的劃分

2.1 用戶空間

  地址範圍:(0 – 0x7FFFFFFF) 2G,運行應用程序的代碼、數據等。


  2.1.1 NULL(空指針區)

    地址範圍:(0 – 0x0000FFFF)


  2.1.2 用戶區

    地址範圍:(0x00010000 – 0x7FFEFFFF)


  2.1.3 64k禁入區(存在於Win XP,Win 7,Win 8 不一定存在)

    地址範圍:(0x7FFEFFFF – 0x7FFFFFFF)


2.2 內核空間

  地址範圍:(0x80000000 – 0xFFFFFFFF) 2G,運行驅動/內核數據和代碼。


地址映射

  1 內存區域

區域指一段連續的地址空間,區域粒度與CPU粒度、操作系統相關。目前,通常以64k粒度存在,地址的對齊方式是以64k爲邊界。

區域的狀態:

1.1 空閒 - 空閒的,可以被使用

1.2 私有已經被佔有,但還未使用

1.3 映像程序的代碼使用(可理解爲代碼段)

1.4 映射程序的數據使用(可理解爲數據段)


  2 物理內存

可實際使用的物理存儲器。


  3 虛擬內存

使用硬盤空間作爲內存的拓展,也可當做物理內存使用。


  4 內存頁

操作系統使用內存頁的方式管理物理內存和虛擬內存。通常情況下,內存頁的大小爲4k/8k(若分配一個字節大小的內存,其實際分配內存大小也爲4k/8k)

每個內存頁具有自己的狀態(只讀/可寫/可執行等)


  5 頁目表

用於管理內存頁的目錄表。

頁目 -  頁表   - 內存頁

                內存頁

     -  頁表   

  -  頁表   

指針  31---------22  21--------12 11----------0

        頁目       頁表     頁表偏移量


  6 地址空間的訪問

6.1 若地址空間已經存在映射好的物理內存(即對應真正的物理內存),直接返回

6.2 若不存在對應的物理內存,系統去虛擬內存查找對應的內存頁。如果未找到,程序報錯

6.3 若在虛擬內存中找到對應內存頁,系統將虛擬內存切換到物理內存中。返回實際物理內存地址,使用數據


  7 內存的使用

7.1 虛擬內存

  適用於大內存分配。一般情況下,如果分配的內存大於1M,應該使用虛擬內存方式分配內存。


7.2 堆內存

  適用於小內存分配。一般情況下,對於小於1M的內存分配使用。例如malloc/new


7.3 堆棧內存

  系統維護的內存區。


使用虛擬內存

  1 虛擬內存

用於大內存,分配速度快。


  2 虛擬內存的使用

2.1 分配內存(VirtualAlloc)

    LPVOIDVirtualAlloc(

    LPVOIDlpAddress,//NULL或者用於提交的內存地址

    DWORDdwSize,//分配大小,一般是頁大小的倍數   DWORD flAlloctionType,//分配方式

    DWORDflProtect);//內存訪問方式

MEM_RESERVE方式只預留地址,不分配內存

MEM_COMMIT方式可對預留地址的內存進行分配,也可直接分配內存

  一次分配的最大空間小於用戶空間(一般爲2G)


2.2 提交內存(VirtualAlloc----MEM_COMMIT)

  pszBuf= (CHAR*)VirtualAlloc(pszBuf,size, MEM_COMMIT, PAGE_READWRITE);


2.3 使用內存

2.4 釋放內存(VirtualFree)

  BOOL VirtualFree(

    LPVOIDlpAddress,//釋放內存地址

    DWORDdwSize,//釋放的大小

    DWORDdwFreeType);//釋放方式


  3 內存信息的獲取

GlobalMemoryStatus – 獲取內存信息的API

Void GLobalMemoryStatus(

LPMEMOEYSTATUS lpBUffer);//獲取的內存信息

GlobalMemoryStatusEx – 獲取函數增API

Void GLobalMemoryStatusEx(

LPMEMOEYSTATUSEX lpBUffer);//獲取的內存信息

 示例代碼:

#include <Windows.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

#pragma warning(disable:4996);


void MemStatus()//打印內存信息
{
	MEMORYSTATUSEX status = { 0 };
	status.dwLength = sizeof(status);
	GlobalMemoryStatusEx(&status);//獲取內存信息

	//打印內存信息
	printf("TotalPhys : %llu\n", status.ullTotalPhys);
	printf("AvailPhys : %llu\n", status.ullAvailPhys);
	printf("TotalPageFile : %llu\n", status.ullTotalPageFile);
	printf("AvailPageFile : %llu\n", status.ullAvailPageFile);
	printf("TotalVirtual : %llu\n", status.ullTotalVirtual);
	printf("AvailVirtual : %llu\n", status.ullAvailVirtual);
	printf("MemoryLoad : %lu\n", status.dwMemoryLoad);


}

void useVirtualMem()//虛擬內存使用
{
	
	MemStatus();
	long long size = 1024 * 1024 * 1024 * sizeof(CHAR);

	//地址分配
	char *pszBuf = (CHAR*)VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE);

	printf("MEM_RESERVE : %p\n", pszBuf);

	//內存提交
	pszBuf = (CHAR*)VirtualAlloc(pszBuf, size, MEM_COMMIT, PAGE_READWRITE);

	MemStatus();

	//使用虛擬內存
	printf("MEM_COMMIT: %p\n", pszBuf);
	strcpy(pszBuf, "Hello VirtualMem!");
	printf("%s\n", pszBuf);

	getch();

	//釋放內存
	VirtualFree(pszBuf, size, MEM_RELEASE);
}

int main()
{
	useVirtualMem();
	return 0;
}

堆內存

  1 堆內存的特點

分配小數據內存,一般小於1M數據時使用堆內存分配。

一般執行程序後,會有一個默認堆,這個堆一般大小爲1M(內存不夠時會自動擴展),一個程序可以有多個堆。通過堆內存管理器管理堆內存。

內存分配速度比VirtualAlloc慢。


  2 堆內存的使用

2.1 創建堆

 

HeapCreate

HANDLE  HeapCreate(//返回堆句柄

        DWORD flOptions,//堆得創建標識

        SIZE_T dwInitialSize,//堆得初始化大小

        SIZE_T dwMaximumSize);//堆的最大大小

2.2 分配內存

  HeapAlloc

LPVOID HeapAlloc(//返回內存指針

       HANDLE hHeap,//堆的句柄

       DWORD dwFlags,//分配標識

       SIZE_T dwBytes);//分配大小(字節)

2.3 使用內存

2.4 釋放內存

  HeapFree

 BOOL  HeapFree(

        HANDLE hHeap,//堆的句柄

        DWORD dwFlags,//釋放標識

 LPVOID lpMem//釋放的地址

    );

 

2.5 釋放堆

 

HeapDestroy

BOOL  HeapDestroy(

HANDLE hHeap);//堆句柄

 

  3 malloc/VirtualAlloc/HeapAlloc

malloc 內部調用HeapAllocHeapAlloc內部調用VirtualAlloc

malloc 分配內存:

例如100個字節

| 內存頭 | 100字節 | 4字節尾部標識|

所有使用malloc分配的內存使用內存頭構成鏈表。


  4 堆的信息

GetProcessHeap() – 當前默認堆的句柄

GetProcessHeaps() – 當前進程所有堆的句柄,返回堆數量

 示例代碼:

#include <Windows.h>
#include <stdio.h>

#pragma warning(disable:4996)


void HeapInfo()//打印堆信息
{
	HANDLE hHeap = GetProcessHeap();
	printf("DefaultHeap: %p\n", hHeap);

	HANDLE hHeaps[256] = { 0 };
	int nHeaps = GetProcessHeaps(256, hHeaps);

	printf("AllHeap: %d\n", nHeaps);
	for (int i = 0; i < nHeaps; ++i)
	{
		printf("\t %d  %p\n", i ,hHeaps[i]);
	}
}

void Heap()
{
	HeapInfo();
	//創建堆
	HANDLE hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS,
		                                     1024 * 1024,
											 0);//設置爲0時,堆內存自動擴展
	printf("HeapCreate: %p\n", hHeap);

	//內存分配
	CHAR *pszBuf = (CHAR*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 100);

	printf("HeapAlloc: %p\n", pszBuf);

	strcpy(pszBuf, "Hello HeapAlloc!");
	printf("%s\n", pszBuf);
	
	HeapInfo();
	//內存釋放
	HeapFree(hHeap, 0, pszBuf);

	//釋放堆
	HeapDestroy(hHeap);
	HeapInfo();
}


int main()
{
	Heap();
	return 0;
}

堆棧內存

  堆棧都是小數據的使用,系統維護,棧的大小一般爲1M

例如Windows使用 _alloca()函數從棧上分配內存。


內存映射文件(大文件數據的讀寫)

  1 內存映射文件的含義

可將文件映射爲內存,可以像使用內存一樣使用文件


  2 內存映射文件的使用

2.1 創建/打開一個文件

  CreateFile()


2.2 創建內存映射文件

  CreateFileMapping()

HANDLE  CreateFileMappingA(

HANDLE hFile, //文件句柄

 LPSECURITY_ATTRIBUTES lpFileMappingAttributes,//     安全屬性

 DWORD flProtect,//保護模式

 DWORD dwMaximumSizeHigh,//映射文件大小的高32位

 DWORD dwMaximumSizeLow,//映射文件大小的低32位

 LPCSTR lpName );//文件映射內核對象的名稱

2.3 將文件映射爲內存地址

 

MapViewOfFile()

LPVOID  MapViewOfFile(

HANDLE hFileMappingObject,//文件映射句柄

DWORD dwDesiredAccess,//訪問模式

DWORD dwFileOffsetHigh,//地址偏移高32位

DWORD dwFileOffsetLow,//地址偏移低32位

SIZE_T dwNumberOfBytesToMap);//要映射的字節數

2.4 使用內存

2.5 卸載映射


  UnMapViewOfFile()

BOOL  UnmapViewOfFile(

 LPCVOID lpBaseAddress);

2.6 關閉映射內存文件

  CloseHandle()

2.7 文件的關閉

  CloseHandle()

 代碼示例:

#include <Windows.h>
#include <stdio.h>

#pragma warning(disable:4996)

void Map()
{
	//創建文件
	HANDLE hFile = CreateFileA("D:\\map.dat", GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	//創建文件映射
	HANDLE hMap = CreateFileMappingA(hFile, NULL, PAGE_READWRITE, 0, 1024 * 1024, NULL);

	//映射地址
	CHAR *pszText = (CHAR*)MapViewOfFileEx(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 1024 * 1024, nullptr);

	//使用內存
	strcpy(pszText, "Hello File Mapping!");
	printf("%s\n", pszText);


	//卸載地址
	UnmapViewOfFile(pszText);
	//關閉文件映射
	CloseHandle(hMap);
	//關閉文件
	CloseHandle(hFile);
}

int main()
{
	Map();
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章