win32day13-地址空间/地址映射/虚拟内存/堆内存/内存映射文件
Posted 吴英强
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了win32day13-地址空间/地址映射/虚拟内存/堆内存/内存映射文件相关的知识,希望对你有一定的参考价值。
地址空间
1 地址空间
一个程序最大的寻址范围。对于Win32操作系统
最大的寻址范围是2的32次方,0-0xFFFFFFFF。
这个寻址范围由CPU决定。CPU的寻址范围越大,
程序难度降低。
2 地址空间的划分
通常情况下:
2.1 用户空间
地址范围 0 - 0x7FFFFFFF(2G),运行
应用程序代码、数据等等。
2.2.1 空指针区(NULL区)
地址范围 0 - 0x0000FFFF
2.2.2 用户区
地址范围 0x00010000 - 0x7FFEFFFF
2.2.3 64K禁入区
地址范围 0x7FFEFFFF - 0x7FFFFFFF
2.2 内核空间
地址范围 0x80000000 - 0xFFFFFFFF,被
系统使用,运行驱动、内核的数据和代码。
地址映射
1 区域
区域指一段连续的地址空间,区域的粒度和
CPU的粒度、操作系统相关。目前通常都是以
64K粒度存在,地址的对齐方式是以64K为边界。
区域的状态:
1)空闲 -空闲的,可以被使用
2)私有 -已经被占有,但是还未使用
3)映像 -程序的代码使用
4)映射 -程序的数据使用
2 物理内存
实际可以使用的物理存储器。
3 虚拟内存
使用硬盘空间作为内存扩展,也可以当作
物理内存使用。
4 内存页
操作系统使用内存页的方式管理物理内存
和虚拟内存。通常情况下,内存页的大小
为4K或者8K。
每个内存页具有自己的状态,例如
只读/可写/可执行
5 页目表
用于管理内存页的表。
页目 - 页表 -内存页
- 内存页
- 页表
- 页表
指针 31 -----22 21-------12 11-----------0
页目 页表 偏移量
6 地址空间的访问
6.1 地址空间已经存在映射好的物理内存,
直接使用,返回。
6.2 系统去虚拟内存中,查找对应的内存页。
如果未找到,系统错误返回。
6.3 系统将虚拟内存的内存页切换到物理
内存当中。
6.4 返回实际物理内存地址,使用数据。
7 内存的使用
7.1 虚拟内存
适合对于大内存分配使用。一般情况下
如果分配的内存大于1M,应该使用虚拟
内存分配方式。
7.2 堆内存
适合对于小内存分配使用。一般情况下
对于小于1M的内存分配使用。例如
malloc/new。
7.3 堆栈内存
系统维护的内存区。
// WinSys.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
void ShowSys( )
SYSTEM_INFO info = 0 ;
GetSystemInfo( &info );
printf( "内存页的大小: %d\\n",
info.dwPageSize );
printf( "可用最小地址: %p\\n",
info.lpMinimumApplicationAddress );
printf( "可用最大地址: %p\\n",
info.lpMaximumApplicationAddress );
printf( "区域的分配粒度: %d\\n",
info.dwAllocationGranularity );
int main(int argc, char* argv[])
ShowSys( );
//错误的地址
//printf( "%d", *((int *)0x0000FFFF) );
return 0;
虚拟内存
1 虚拟内存
常用于大内存分配,分配的速度快,可以
根据需要指定分配方式。
2 虚拟内存的使用
2.1 分配内存
LPVOID VirtualAlloc(
LPVOID lpAddress,//NULL或者用于提交的内存地址
DWORD dwSize,//分配的大小,一般是页倍数
DWORD flAllocationType,//分配的方式
DWORD flProtect );//内存访问方式
分配的最大空间小于用户区间(通常是2G)。
2.2 提交内存
VirtualAlloc使用MEM_COMMIT方式。例如:
pszBuf = (CHAR *)
VirtualAlloc(
pszBuf, //需要提交内存地址
1024 * 1024 * 1024,
MEM_COMMIT,
PAGE_READWRITE );
2.3 使用内存
2.4 释放内存
BOOL VirtualFree(
LPVOID lpAddress,//释放的内存
DWORD dwSize, //释放的大小
DWORD dwFreeType ); //释放的方式
3 内存信息
VOID GlobalMemoryStatus(
LPMEMORYSTATUS lpBuffer //获取内存信息
);
// WinVirtual.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "conio.h"
#include "windows.h"
void Status( )
//获取内存信息
MEMORYSTATUS status = 0 ;
status.dwLength = sizeof( status );
GlobalMemoryStatus( &status );
printf( "TotalPhys: %u\\n", status.dwTotalPhys );
printf( "AvailPhys: %u\\n", status.dwAvailPhys );
printf( "TotalPageFile: %u\\n", status.dwTotalPageFile );
printf( "AvailPageFile: %u\\n", status.dwAvailPageFile );
printf( "TotalVirtual: %u\\n", status.dwTotalVirtual );
printf( "AvailVirtual: %u\\n", status.dwAvailVirtual );
printf( "MemoryLoad: %d\\n", status.dwMemoryLoad );
void Virtual( )
Status( );
//地址分配
CHAR * pszBuf = (CHAR *)
VirtualAlloc( NULL,
1024 * 1024 * 1024,
MEM_RESERVE,
PAGE_READWRITE );
printf( "MEM_RESERVE: %p\\n", pszBuf );
Status( );
getch( );
//内存提交
pszBuf = (CHAR *)
VirtualAlloc( pszBuf,
1024 * 1024 * 1024,
MEM_COMMIT,
PAGE_READWRITE );
printf( "MEM_COMMIT: %p\\n", pszBuf );
Status( );
strcpy( pszBuf, "hello Virtual" );
printf( "%s\\n", pszBuf );
Status( );
getch( );
//释放内存
VirtualFree( pszBuf,
1024 * 1024 * 1024,
MEM_RELEASE );
int main(int argc, char* argv[])
Virtual( );
return 0;
堆内存
1 堆内存的特点
一般分配小数据内存,一般小于1M数据使用堆内存分配。
一般程序执行后,会有一个默认堆,这个堆的大小一般为1M。一个程序可以多个堆。通
过堆内存管理器来管理堆中的内存。
内存分配速度比VirtualAlloc慢。
2 堆内存的使用
2.1 创建堆
HANDLE HeapCreate(
DWORD flOptions,//创建标示
DWORD dwInitialSize, //初始化大小
DWORD dwMaximumSize ); //最大大小
2.2 分配内存
LPVOID HeapAlloc(
HANDLE hHeap, //堆的句柄
DWORD dwFlags, //分配标示
DWORD dwBytes ); //分配大小
2.3 使用内存
2.4 释放内存
BOOL HeapFree(
HANDLE hHeap, //堆的句柄
DWORD dwFlags, //释放标示
LPVOID lpMem ); //释放的地址
2.5 释放堆
BOOL HeapDestroy(
HANDLE hHeap ); //堆的句柄
3 malloc/HeapAlloc/VirtualAlloc
malloc内部调用HeapAlloc。
HeapAlloc内部调用的VirtualAlloc。
malloc分配内存:
例如100字节
| 内存头 | 100字节| 4字节尾部标示|
所用使用malloc分配的内存,会使用这个
内存头构成链表.
4 堆的信息
GetProcessHeap 当前进程默认堆的句柄
GetProcessHeaps 当前进程所有堆的句柄
四 堆栈内存
堆栈都是小数据的使用,系统维护,栈的大小
一般在1M左右.
例如,Windows下可以使用_alloca函数从栈上
分配内存.
// WinHeap.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdlib.h"
#include "windows.h"
void HeapInfo( )
//默认堆的句柄
HANDLE hHeap = GetProcessHeap();
printf( "Default Heap: %p\\n", hHeap );
//所有的堆的句柄
HANDLE hHeaps[256] = 0 ;
DWORD nCount =
GetProcessHeaps( 256, hHeaps );
printf( "All Heap: %d\\n", nCount );
for( DWORD nIndex=0; nIndex<nCount; nIndex++ )
printf( "\\t%d: %p\\n", nIndex+1,
hHeaps[nIndex] );
void Heap( )
HeapInfo( );
//创建堆
HANDLE hHeap = HeapCreate(
HEAP_GENERATE_EXCEPTIONS,
1024 * 1024, 0 );
printf( "HeapCreate: %p\\n", hHeap );
HeapInfo( );
//内存分配
CHAR * pszBuf = ( CHAR * )
HeapAlloc( hHeap, HEAP_ZERO_MEMORY, 100 );
printf( "HeapAlloc: %p\\n", pszBuf );
strcpy( pszBuf, "hello Heap" );
printf( "%s\\n", pszBuf );
//内存释放
HeapFree( hHeap, 0, pszBuf );
//释放堆
HeapDestroy( hHeap );
HeapInfo( );
int main(int argc, char* argv[])
CHAR * pszBuf = (CHAR *)malloc( 1024 );
Heap( );
return 0;
内存映射文件
1 内存映射文件
可以将文件映射成内存,我们可以像使用内
存一样使用文件.
2 内存映射文件的使用
2.1 创建或打开一个文件
CreateFile
2.2 创建内存映射文件
HANDLE CreateFileMapping(
HANDLE hFile, //文件句柄
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
//安全属性
DWORD flProtect, //保护模式
DWORD dwMaximumSizeHigh,//大小的高32位
DWORD dwMaximumSizeLow, //大小的低32位
LPCTSTR lpName ); //文件映射内核对象的名称
2.3 映射成内存地址
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, //文件映射句柄
DWORD dwDesiredAccess, //访问模式
DWORD dwFileOffsetHigh, //地址偏移高32位
DWORD dwFileOffsetLow,//地址偏移低32位
DWORD dwNumberOfBytesToMap ); //要映射的字节数
2.4 使用内存
2.5 卸载映射
BOOL UnmapViewOfFile(
LPCVOID lpBaseAddress //卸载的地址
);
2.6 关闭内存映射文件
CloseHandle
2.7 文件关闭
CloseHandle
// WinMap.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
void Map( )
//创建文件
HANDLE hFile = CreateFile( "C:\\\\map.dat",
GENERIC_READ|GENERIC_WRITE,
0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL );
//创建文件映射
HANDLE hMap = CreateFileMapping( hFile, NULL,
PAGE_READWRITE, 0, 1024 * 1024, NULL );
//映射地址
CHAR * pszText = (CHAR *)MapViewOfFile(
hMap, FILE_MAP_ALL_ACCESS,
0, 0, 1024 * 1024 );
//使用内存
strcpy( pszText, "Hello File Mapping" );
printf( "%s\\n", pszText );
//卸载地址
UnmapViewOfFile( pszText );
//关闭文件映射
CloseHandle( hMap );
//关闭文件
CloseHandle( hFile );
int main(int argc, char* argv[])
Map( );
return 0;
以上是关于win32day13-地址空间/地址映射/虚拟内存/堆内存/内存映射文件的主要内容,如果未能解决你的问题,请参考以下文章
Linux 操作系统原理 — 内存管理 — 虚拟地址空间(x86 32bit 系统)