📄 sy0501.htm
字号:
<html>
<HEAD>
<TITLE>Visual C++与计算机接口</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=gb2312" >
</HEAD>
<body>
<font color="#0000FF">Win32内存管理</font>
<p>
(一)实验目的:<BR>
学习Win32内存管理<BR><BR>
(二)实验内容:<BR><BR>
1、进程和内存空间<BR>
Win32中,每个运行的程序就是一个进程,它由两个部分组成:<BR>
·操作系统用来管理进程的内核对象<BR>
·地址空间<BR>
内核对象也是系统用来存放关于进程的统计信息的地方。地址空间则包含所有可执行模块或DLL模块的代码和数据,它还包含动态内存分配的空间。如线程堆栈和堆分配空间。<BR><BR>
关于进程最重要的是,它拥有自己“私有”的虚拟地址空间。<BR>
对于32位进程来说,这个地址空间是4GB,因为32位指针可以拥有从0x00000000至0xFFFFFFFF之间的任何一个值。这使得一个指针能够拥有4294967296个值中的一个值,它覆盖了一个进程的4GB虚拟空间的范围。<BR>
因此当一个进程正在运行时,该进程只可以访问属于它的内存。属于所有其他进程的内存则隐藏着,并且不能被正在运行的进程访问。<BR><BR>
2、分页技术<BR>
注意,虚拟地址空间并不是实际的物理存储单元,更不是物理内存。<BR>
进程的4GB地址空间一般不会全部使用到,各种代码和数据被分散到4GB地址空间里,以4KB为边界,每个单元为4KB大小。<BR>
这样每个4KB单元称为一页,如果一页被使用了,它就占用了物理存储单元(但我们并不能看到也不需关心它的物理内存地址)。<BR><BR>
虚拟内存页有4种状态:<BR>
·提交页面:它被分配一个物理存储单元,在内存中或交换文件中。<BR>
·锁定页面:它被强行留在物理内存中,直到解锁为止。<BR>
·保留页面:这段地址将被保留,不会再被分配,但它并不被分配一个物理存储单元。<BR>
·自由页面<BR><BR>
3、内存异常<BR>
当程序要使用一个未被分配物理存储单元的页面时,无论是自由页面还是保留页面,就会产生内存异常。<BR>
初学者最常引起内存异常的地方,是当使用一个未分配内存的指针时,还有当访问内存越界。<BR><BR>
4、VirtualAlloc函数<BR>
在Win32环境下,我们可以使用的内存分配方法有:<BR>
·C:malloc/free<BR>
·C++:new/delete<BR>
·为兼容Win16留下的API:GlobalAlloc/GlobalFree,LocalAlloc/LocalFree<BR>
·堆函数:HeapAlloc/HeapFree<BR>
·虚拟内存函数:VirtualAlloc/VirtualFree<BR>
所有这些方法最终都会调用VirtualAlloc/VirtualFree。<BR><BR>
首先必须知道保留(Reserved)内存和提交(Committed)内存的含义。<BR>
当内存被保留时,一段连续虚拟地址空间被留出,但此时没有物理RAM被分配。<BR>
当我们实际需要使用这段内存时,我们可以再次调用函数VirtualAlloc来提交被保留的内存空间,此时系统才真正分配物理内存。<BR><BR>
VirtualAlloc的三种常用调用方法,注意size的单位是字节:<BR>
(1)直接申请提交内存:<BR>
int* p = (int*) VirtualAlloc (NULL, size, MEM_COMMIT, PAGE_READWRITE);<BR>
(2)申请保留内存<BR>
int* p = (int*) VirtualAlloc (NULL, size, MEM_RESERVE, PAGE_READWRITE);<BR>
(3)提交保留内存<BR>
VirtualAlloc (p, size, MEM_COMMIT, PAGE_READWRITE);<BR><BR>
VirtualFree的两种常用调用方法<BR>
(1)将内存由提交内存变为保留内存,这段内存中可以既包括提交页面也包括保留页面:<BR>
VirtualFree (p, size, MEM_DECOMMIT);<BR>
(2)释放内存,这段内存中可以既包括提交页面也包括保留页面:<BR>
VirtualFree (p, 0, MEM_RELEASE);<BR>
注意,p必须为VirtualAlloc返回的指针,长度必须填为0,否则出错。<BR><BR>
5、保留内存与提交内存的一个实例<BR><BR>
假设想实现一个电子表格应用程序,这个电子表格为200行x256列。对于每一个单元格,都需要一个CELLDATA结构来描述单元格的内容。<BR>
要处理这种二维单元格矩阵,最容易的方法是在应用程序中声明下面的变量:<BR>
CELLDATA CellData[200][256];<BR>
如果CELLDATA结构的大小是128字节,那么这个二维矩阵将需要6553600(200 x 256 x 128)个字节的存储器。<BR>
如果这些内存都直接用页文件来分配物理存储器,那么这是个不小的数目。尤其是考虑到大多数用户只是将信息放入少数的单元格中,而大部分单元格却空闲不用,因此显得有些浪费。内存的利用率非常低。<BR><BR>
传统上,电子表格一直是用其他数据结构技术来实现的,比如链接表等。<BR>
使用链接表,只需要为电子表格中实际包含数据的单元格创建CELLDATA结构。由于电子表格中的大多数单元格都是不用的,因此这种方法可以节省大量的内存。<BR>
但是这种方法使得你很难获得单元格的内容。如果想知道第5行第10列的单元格的内容,必须遍历链接表,才能找到需要的单元格,因此使用链接表方法比明确声明的矩阵方法速度要慢。<BR>
虚拟内存为我们提供了一种兼顾预先声明二维矩阵和实现链接表的两全其美的方法。<BR>
运用虚拟内存,既可以使用已声明的矩阵技术进行快速而方便的访问,又可以利用链接表技术大大节省内存的使用量。<BR>
利用虚拟内存技术的优点,程序可以按照下列步骤来编写:<BR>
(1) 保留一个足够大的地址空间区域,用来存放CELLDATA结构的整个数组。保留一个根本不使用任何物理存储器的区域。<BR>
(2) 当用户将数据输入一个单元格或对单元格进行其它操作时,找出CELLDATA结构应该进入的保留区域中的内存地址。当然,这时尚未有任何物理存储器被映射到该地址,因此,访问该地址的内存的任何企图都会引发访问违规。<BR>
(3) 将上一步中找到的内存地址以及所需的地址范围,提交给系统来分配物理存储器。这个范围既可以包含已经提交过的地址,也可以包含没有提交过的地址。<BR>
(4) 操作单元格,即设置CELLDATA对象属性。<BR><BR>
现在物理存储器已经映射到相应的位置,你的程序能够访问内存,而不会引发访问违规。这个虚拟内存技术非常出色,因为只有在用户将数据输入电子表格的单元格时,才会提交物理存储器。由于电子表格中的大多数单元格是空的,因此大部分保留区域没有提交给它的物理存储器。<BR>
</p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -