VC实现内存管理源代码!-----高手请进! 现在我急需一个内存管理的代码实例,有哪位高手可以提供一下,这里先谢谢了!我的信箱是[email protected]. 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 6.1 Win32下的内存管理介绍 在使用C语言是可以利用ANSI C的库函数alloc来分配或者用C++的new操作符来分配,内存但是对于一个操作系统来说利用系统提供的API函数来进行内存分配,这样可以更加有效的利用内存。 在Windows 3.X的时代,分配的内存可以有两种,全局的和局部的,例如GlobalAlloc和LocalAlloc。但在Win32的时代这些函数已经被废弃了,现在的内存只有一种就是虚存。在Win32中所有的进程所使用的内存区域是相互隔离的,每个进程都拥有自己的地址空间。而且系统使用了页面交换功能,就是利用磁盘空间来模拟RAM,在RAM中数据不使用时将会被交换到磁盘,在需要时将会被重新装入RAM。 在Win32中每个进程的地址空间为4GB,从0X00000000到0XFFFFFFFF。对于M$不同的操作系统来讲,应用程序可以使用地址空间是不同的。 Windows 9X 范围 作用 0X00000000 - 0X00000FFF MS DOS 0X00001000 - 0X003FFFFF 16位Windows 0X40000000 - 0X7FFFFFFF Win32应用程序 0X80000000 - 0XBFFFFFFF 内存映射文件,由Win32进程共享 0XC0000000 - 0XFFFFFFFF 操作系统 Windows NT/2000 范围 作用 0X00000000 - 0X7FFFFFFF Win32应用程序 0X80000000 - 0XFFFFFFFF 操作系统 Windows NT Server Enterprise Edition/Windows 2000 Advanced Server 范围 作用 0x00000000 - 0xBFFFFFFF Win32应用程序 0xC0000000 - 0XFFFFFFFF 操作系统 在系统中内存的最小单位是页,一页的大小不同,例如在Intel系统上Windows9X下一页的大小位4K,而在Alpha系统上NT下一页的大小为8K。通过GetSystemInfo函数可以获得系统信息: VOID GetSystemInfo( LPSYSTEM_INFO lpSystemInfo // system information);typedef struct _SYSTEM_INFO { union { DWORD dwOemId; struct { WORD wProcessorArchitecture; WORD wReserved; }; }; DWORD dwPageSize; //页大小 LPVOID lpMinimumApplicationAddress; //应用程序可以使用的最小地址 LPVOID lpMaximumApplicationAddress; //应用程序可以使用的最大地址 DWORD_PTR dwActiveProcessorMask; DWORD dwNumberOfProcessors; //CPU数量 DWORD dwProcessorType; //CPU类型 DWORD dwAllocationGranularity; WORD wProcessorLevel; WORD wProcessorRevision; } SYSTEM_INFO; 在Win32系统中内存页是可以设定保护方式(存取权限)的(例如可以设定某个内存页为只读,那么如果对这段内存进行写就会引发异常,而通过alloc或new分配的内存却不可以设置存取权限)。对内存的使用方式为先申请一段保留空间,然后提交这段内存空间并设置保护方式(申请和提交可以在一个步骤内完成),之后就可以对提交的内存区域进行操作,如果有必要可以改变内存的保护方式,在不在使用时回收内存,最后释放保留的内存空间。 对于很多关键性的应用来将自己管理内存的使用是很重要的,因为这样可以利用系统特性来提高应用性能和对内存的利用。对于桌面应用程序来说一般不需要直接使用系统提供的虚存管理API。 返回版权所有 闻怡洋 http://www.vchelp.net/ 6.2 虚存的使用 虚存的分配通过VirtualAlloc函数来完成,对于内存的分配和提交是以页为单位的,如果要求分配的内存大小不为页的整数倍,系统将会加大内存达到页的整数倍,而且会将申请的地址设定在页的边界,所以在申请时尽量按照页来进行申请。 LPVOID VirtualAlloc( LPVOID lpAddress, // region to reserve or commit SIZE_T dwSize, // size of region DWORD flAllocationType, // type of allocation DWORD flProtect // type of access protection);lpAddress 为申请的内存地址,在Win32中你可以自己指定申请内存的地址范围,如果为NULL则由系统分配一段空闲的地址 dwSize 内存大小,以字节为单位 flAllocationType 申请方式,可以取下面的值的组合: MEM_RESERVE 要求系统保留申请的地址,如果申请成功,这段地址就无法再次被申请 MEM_COMMIT 提交已经申请的内存 MEM_TOP_DOWN 在由系统指定地址时要求系统从空闲区域的顶部开始分配,这样可以减少内存碎片 flProtect 指定内存的保护方式,可以选用下面的值: PAGE_READONLY 只读 PAGE_READWRITE 读写 PAGE_EXECUTE 执行 PAGE_EXECUTE_READ 执行和读取 PAGE_EXECUTE_READWRITE 执行和读写 PAGE_NOACCESS 不允许任何存取 如果函数执行成功会返回要求的地址,否则将会返回NULL。 一段内存在申请后并不能马上使用,如果要使用必须先提交,并且在提交时指定内存的保护方式。对于未申请或已经申请但未提交的内存的任何操作都将会引发异常。 如果要释放或回收已经提交的内存可以使用VirtualFree: BOOL VirtualFree( LPVOID lpAddress, // 地址 SIZE_T dwSize, // 大小 DWORD dwFreeType // 释放方式 // MEM_DECOMMIT 回收已经提交的虚存 //MEM_RELEASE 释放已经申请的虚存,dwSize这是必须为0);下面有一些例子可以帮助理解虚存的使用: //eg 1pMem = VirtualAlloc(NULL,1024*64*2,MEM_RESERVE,0); //申请128K虚存,地址由系统指定if(pMem) //假设返回值为 0X10000000{ pMem2 =VirtualAlloc(pMem + 0X1000,1024*32,MEM_COMMIT,PAGE_READWRITE); //提交32K内存 if(pMem2)// pMem2=0X10010000 { memcpy(pMem2,p,32*1024);//对内存进行写 memcpy(p2,pMem2,32*1024);//对内存进行读 VirtualFree(pMem2,1024*32,MEM_DECOMMIT);//回收 } VirtualFree(pMem,0,MEM_RELEASE);//释放}//eg 2pMem = VirtualAlloc((LPVOID)0X10000000,1024*64*2,MEM_RESERVE | MEM_COMMIT,PAGE_READWRITE); //由0X10000000开始的128K虚存并同时提交该虚存,保护方式为可以读和写if(pMem) { memcpy(pMem,p,32*1024);//对内存进行写 memcpy(p2,pMem,32*1024);//对内存进行读 VirtualFree(pMem,1024*64*2,MEM_DECOMMIT);//回收 VirtualFree(pMem,0,MEM_RELEASE);//释放}//eg 3pMem = VirtualAlloc((LPVOID)0X10000000,1024*64*2,MEM_RESERVE | MEM_COMMIT,PAGE_READ); //由0X10000000开始的128K虚存并同时提交该虚存,保护方式为只读if(pMem) { memcpy(p2,pMem,32*1024);//对内存进行读 memcpy(pMem,p,32*1024);//对内存进行写 引发异常,因为该段内存不允许写 ...}在虚存被提交后可以修改虚存的保护方式,例如在你完成了数据写后可以将内存设置为只读,这样可以放置数据被错误的修改,函数为: BOOL VirtualProtect( LPVOID lpAddress, // 地址 SIZE_T dwSize, // 大小 DWORD flNewProtect, // 新的保护方式 PDWORD lpflOldProtect // 旧的保护方式);你可以在使用虚存时先取得虚存的状态,函数为: DWORD VirtualQuery( LPCVOID lpAddress, // 地址 PMEMORY_BASIC_INFORMATION lpBuffer, // 返回的数据 DWORD dwLength // 虚存大小);typedef struct _MEMORY_BASIC_INFORMATION { PVOID BaseAddress; // 查询的地址 PVOID AllocationBase; // 分配的地址 DWORD AllocationProtect; // 申请虚存时设定的保护方式 SIZE_T RegionSize; // 虚存大小 DWORD State; //当前状态 //MEM_FREE 还为被申请 //MEM_RESERVE 已经被申请,但未被提交 //MEM_COMMIT 已经被提交 DWORD Protect; // 提交虚存时设定的保护方式 DWORD Type; // } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; 本节提供一个例子来帮助大家理解虚存的使用,这个程序具有下面的界面:你可以点击按钮来执行指定功能,你可以试试看在会提交虚存时进行读写所引发的异常,和在设定为只读时对虚存进行写操作所引发的异常。 下载示范代码 此外对虚存可以进行加锁和解锁操作,经过加锁的虚存在不会被系统交换到磁盘上而始终被保存在RAM中。但加锁虚存可能会引起系统性能的下降,所以系统不允许同一进程加锁30页以上虚存,并且如果保护方式为PAGE_NOACCESS 的页。函数为: BOOL VirtualLock( LPVOID lpAddress, // 地址 SIZE_T dwSize // 加锁的虚存大小,单位为字节);BOOL VirtualUnlock( LPVOID lpAddress, // 地址 SIZE_T dwSize // 解锁的虚存大小,单位为字节);和虚存的分配和提交一样,加锁和解锁也是以页为单位的,即使你加锁2个字节也会引起对所在页的加锁。建议开发过程中如果没有非常的必要不要对虚存进行加锁。 http://www.vchelp.net/vchelp/zteach/sam_sp_62.zip 要求编写一个包含两个线程的进程,一个线程从一个文件中读出要进行的内存操作,内存操作包括:时间:开始的执行时间。块数:分贝内存的粒度。操作:包括保留一个区域,提交一个区域,释放一个区域,回收一个区域,以及加锁和解锁一个区域,可以将这些操作编号,存放于文件中。大小:指块的大小。访问权限:共五种PAGE_READONLY PAGE_READWRITE PAGE_EXECUTE PAGE_EXECUTE_READ PAGE_EXECUTE_READWRITE。可以将这些权限编号,存放于文件中。另一个线程将页面大小、已使用的地址范围、物理内存总量以及虚拟内存等信息显示出来。 终于实现了!在这里要感谢大家的支持。特别是 Skt32(荒城之月) 给我提供的例子。如果有朋友需要我的例子的话说一声我上传过来! 我要,你传一个给我,谢谢。[email protected] 我的邮箱 [email protected] TreeCtrl的讨论.. 请问一个以IE为当前进程来createProcess的问题 请教DDraw问题 小弟新来的,请各位多多关照。 请问,全局钩子的参数是怎么样的? 急急急, ACCESS中没有与SQL SERVER的NEWID()相同功能的函数啊,ONLINE! 关于Socket的多线程问题! 一道题 低分求解(是我没得分了),如何将内存中的HTML代码直接写到HTMLVIEW视中,不要用临时文件! 各位,大家经常呆在电脑前编程,显示器一定很重要把,请帮我推荐一台!!!谢了!! 高手们:mfc编程中如何为dialog在标题栏增加"按钮",谢谢! 软件创意可以得到保护?
范围 作用
0X00000000 - 0X00000FFF MS DOS
0X00001000 - 0X003FFFFF 16位Windows
0X40000000 - 0X7FFFFFFF Win32应用程序
0X80000000 - 0XBFFFFFFF 内存映射文件,由Win32进程共享
0XC0000000 - 0XFFFFFFFF 操作系统
Windows NT/2000
范围 作用
0X00000000 - 0X7FFFFFFF Win32应用程序
0X80000000 - 0XFFFFFFFF 操作系统
Windows NT Server Enterprise Edition/Windows 2000 Advanced Server
范围 作用
0x00000000 - 0xBFFFFFFF Win32应用程序
0xC0000000 - 0XFFFFFFFF 操作系统
在系统中内存的最小单位是页,一页的大小不同,例如在Intel系统上Windows9X下一页的大小位4K,而在Alpha系统上NT下一页的大小为8K。通过GetSystemInfo函数可以获得系统信息: VOID GetSystemInfo(
LPSYSTEM_INFO lpSystemInfo // system information
);
typedef struct _SYSTEM_INFO {
union {
DWORD dwOemId;
struct {
WORD wProcessorArchitecture;
WORD wReserved;
};
};
DWORD dwPageSize; //页大小
LPVOID lpMinimumApplicationAddress; //应用程序可以使用的最小地址
LPVOID lpMaximumApplicationAddress; //应用程序可以使用的最大地址
DWORD_PTR dwActiveProcessorMask;
DWORD dwNumberOfProcessors; //CPU数量
DWORD dwProcessorType; //CPU类型
DWORD dwAllocationGranularity;
WORD wProcessorLevel;
WORD wProcessorRevision;
} SYSTEM_INFO; 在Win32系统中内存页是可以设定保护方式(存取权限)的(例如可以设定某个内存页为只读,那么如果对这段内存进行写就会引发异常,而通过alloc或new分配的内存却不可以设置存取权限)。对内存的使用方式为先申请一段保留空间,然后提交这段内存空间并设置保护方式(申请和提交可以在一个步骤内完成),之后就可以对提交的内存区域进行操作,如果有必要可以改变内存的保护方式,在不在使用时回收内存,最后释放保留的内存空间。 对于很多关键性的应用来将自己管理内存的使用是很重要的,因为这样可以利用系统特性来提高应用性能和对内存的利用。对于桌面应用程序来说一般不需要直接使用系统提供的虚存管理API。
返回版权所有 闻怡洋 http://www.vchelp.net/
6.2 虚存的使用 虚存的分配通过VirtualAlloc函数来完成,对于内存的分配和提交是以页为单位的,如果要求分配的内存大小不为页的整数倍,系统将会加大内存达到页的整数倍,而且会将申请的地址设定在页的边界,所以在申请时尽量按照页来进行申请。 LPVOID VirtualAlloc(
LPVOID lpAddress, // region to reserve or commit
SIZE_T dwSize, // size of region
DWORD flAllocationType, // type of allocation
DWORD flProtect // type of access protection
);lpAddress 为申请的内存地址,在Win32中你可以自己指定申请内存的地址范围,如果为NULL则由系统分配一段空闲的地址 dwSize 内存大小,以字节为单位 flAllocationType 申请方式,可以取下面的值的组合:
MEM_RESERVE 要求系统保留申请的地址,如果申请成功,这段地址就无法再次被申请
MEM_COMMIT 提交已经申请的内存
MEM_TOP_DOWN 在由系统指定地址时要求系统从空闲区域的顶部开始分配,这样可以减少内存碎片
flProtect 指定内存的保护方式,可以选用下面的值:
PAGE_READONLY 只读
PAGE_READWRITE 读写
PAGE_EXECUTE 执行
PAGE_EXECUTE_READ 执行和读取
PAGE_EXECUTE_READWRITE 执行和读写
PAGE_NOACCESS 不允许任何存取
如果函数执行成功会返回要求的地址,否则将会返回NULL。
一段内存在申请后并不能马上使用,如果要使用必须先提交,并且在提交时指定内存的保护方式。对于未申请或已经申请但未提交的内存的任何操作都将会引发异常。 如果要释放或回收已经提交的内存可以使用VirtualFree: BOOL VirtualFree(
LPVOID lpAddress, // 地址
SIZE_T dwSize, // 大小
DWORD dwFreeType // 释放方式
// MEM_DECOMMIT 回收已经提交的虚存
//MEM_RELEASE 释放已经申请的虚存,dwSize这是必须为0
);下面有一些例子可以帮助理解虚存的使用: //eg 1
pMem = VirtualAlloc(NULL,1024*64*2,MEM_RESERVE,0); //申请128K虚存,地址由系统指定
if(pMem) //假设返回值为 0X10000000
{
pMem2 =VirtualAlloc(pMem + 0X1000,1024*32,MEM_COMMIT,PAGE_READWRITE); //提交32K内存
if(pMem2)// pMem2=0X10010000
{
memcpy(pMem2,p,32*1024);//对内存进行写
memcpy(p2,pMem2,32*1024);//对内存进行读
VirtualFree(pMem2,1024*32,MEM_DECOMMIT);//回收
}
VirtualFree(pMem,0,MEM_RELEASE);//释放
}
//eg 2
pMem = VirtualAlloc((LPVOID)0X10000000,1024*64*2,MEM_RESERVE | MEM_COMMIT,PAGE_READWRITE);
//由0X10000000开始的128K虚存并同时提交该虚存,保护方式为可以读和写
if(pMem)
{
memcpy(pMem,p,32*1024);//对内存进行写
memcpy(p2,pMem,32*1024);//对内存进行读
VirtualFree(pMem,1024*64*2,MEM_DECOMMIT);//回收
VirtualFree(pMem,0,MEM_RELEASE);//释放
}//eg 3
pMem = VirtualAlloc((LPVOID)0X10000000,1024*64*2,MEM_RESERVE | MEM_COMMIT,PAGE_READ);
//由0X10000000开始的128K虚存并同时提交该虚存,保护方式为只读
if(pMem)
{
memcpy(p2,pMem,32*1024);//对内存进行读
memcpy(pMem,p,32*1024);//对内存进行写 引发异常,因为该段内存不允许写
...
}在虚存被提交后可以修改虚存的保护方式,例如在你完成了数据写后可以将内存设置为只读,这样可以放置数据被错误的修改,函数为: BOOL VirtualProtect(
LPVOID lpAddress, // 地址
SIZE_T dwSize, // 大小
DWORD flNewProtect, // 新的保护方式
PDWORD lpflOldProtect // 旧的保护方式
);你可以在使用虚存时先取得虚存的状态,函数为: DWORD VirtualQuery(
LPCVOID lpAddress, // 地址
PMEMORY_BASIC_INFORMATION lpBuffer, // 返回的数据
DWORD dwLength // 虚存大小
);
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress; // 查询的地址
PVOID AllocationBase; // 分配的地址
DWORD AllocationProtect; // 申请虚存时设定的保护方式
SIZE_T RegionSize; // 虚存大小
DWORD State; //当前状态
//MEM_FREE 还为被申请
//MEM_RESERVE 已经被申请,但未被提交
//MEM_COMMIT 已经被提交
DWORD Protect; // 提交虚存时设定的保护方式
DWORD Type; //
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; 本节提供一个例子来帮助大家理解虚存的使用,这个程序具有下面的界面:你可以点击按钮来执行指定功能,你可以试试看在会提交虚存时进行读写所引发的异常,和在设定为只读时对虚存进行写操作所引发的异常。 下载示范代码 此外对虚存可以进行加锁和解锁操作,经过加锁的虚存在不会被系统交换到磁盘上而始终被保存在RAM中。但加锁虚存可能会引起系统性能的下降,所以系统不允许同一进程加锁30页以上虚存,并且如果保护方式为PAGE_NOACCESS 的页。函数为: BOOL VirtualLock(
LPVOID lpAddress, // 地址
SIZE_T dwSize // 加锁的虚存大小,单位为字节
);
BOOL VirtualUnlock(
LPVOID lpAddress, // 地址
SIZE_T dwSize // 解锁的虚存大小,单位为字节
);和虚存的分配和提交一样,加锁和解锁也是以页为单位的,即使你加锁2个字节也会引起对所在页的加锁。建议开发过程中如果没有非常的必要不要对虚存进行加锁。
时间:开始的执行时间。
块数:分贝内存的粒度。
操作:包括保留一个区域,提交一个区域,释放一个区域,回收一个区域,以及加锁和解锁一个区域,可以将这些操作编号,存放于文件中。
大小:指块的大小。
访问权限:共五种PAGE_READONLY PAGE_READWRITE PAGE_EXECUTE PAGE_EXECUTE_READ PAGE_EXECUTE_READWRITE。可以将这些权限编号,存放于文件中。
另一个线程将页面大小、已使用的地址范围、物理内存总量以及虚拟内存等信息显示出来。