写在前面

又到了 一年一度期末课设的时候,距离考试还有12天的时间,此时胡小宁还没有复习(准确的说是学习)之前的课程,所以在这个平平无奇的周二,胡小宁就要开始做课设了!

实验目的

(1) 通过对 Windows xp/7“任务管理器”、“计算机管理”、“我的电脑”属性、“系统信息”、“系统监视器”等程序的应用,学习如何察看和调整 Windows 的内存性能,加深对操作系统内存管理、虚拟存储管理等理论知识的理解。

(2) 了解 Windows xp/7 的内存结构和虚拟内存的管理,理解进程的虚拟内存空间和物理内存的映射关系。

总体设计

背景知识

耗尽内存是 Windows 系统中最常见的问题之一。当系统耗尽内存时,所有进程对内存的总需求超出了系统的物理内存总量。随后,Windows 必须借助它的虚拟内存来维持系统和进程的运行。虚拟内存机制是 Windows 操作系统的重要组成部分,但它的速度比物理内存慢得多,因此,应该尽量避免耗尽物理内存资源,以免导致性能下降。解决内存不足问题的一个有效的方法就是添加更多的内存。但是,一旦提供了更多的内存,Windows 很可以会立即“吞食”。而事实上,添加更多的内存并非总是可行的,也可能只是推迟了实际问题的发生。因此,应该相信,优化所拥有的内存是非常关键的。

(1) 分页过程

当 Windows 求助于硬盘以获得虚拟内存时,这个过程被称为分页 (paging) 。分页就是将信息从主内存移动到磁盘进行临时存储的过程。当进程需要已经交换到硬盘上的代码或数据时,系统要将数据送回物理内存,并在必要时将其他信息传输到硬盘上,而硬盘与物理内存在性能上的差异极大。例如,硬盘的访问时间通常大约为 4-10 毫秒,而物理内存的访问时间为 60us,甚至更快。

(2) 内存共享

应用程序经常需要彼此通信和共享信息。为了提供这种能力,Windows 必须允许访问某些内存空间而不危及它和其他应用程序的安全性和完整性。从性能的角度来看,共享内存的能力大大减少了应用程序使用的内存数量。

(3) 未分页合并内存与分页合并内存

Windows 决定了系统内存组件哪些可以以及哪些不可以交换到磁盘上。显然,不应该将某些代码 (例如内核) 交换出主内存。因此,Windows 将系统使用的内存进一步划分为未分页合并内存和分页合并内存。分页合并内存是存储迟早需要的可分页代码或数据的内存部分。虽然可以将分页合并内存中的任何系统进程交换到磁盘上,但是它临时存储在主内存的这一部分,以防系统立刻需要它。在将系统进程交换到磁盘上之前,Windows 会交换其他进程。

未分页合并内存包含必须驻留在内存中的占用代码或数据。这种结构类似于早期的 MS-DOS

程序使用的结构,在 MS-DOS 中,相对较小的终止并驻留程序 (Terminate and Stay Resident,TSR) 在启动时加载到内存中。这些程序在系统重新启动或关闭之前一直驻留在内存的特定部分中。

(4)分页文件最重要的配置参数是大小。无论系统中有多少个分页文件,如果它们的大小不合适,那么系统就可能遇到性能问题。

如果初始值太小,那么系统可能必须扩大分页文件,以补偿额外的分页活动。当系统临时增加分页文件时,它必须在处理分页请求的同时创建新的空间。这时,系统将出现大量的页面错误,甚至可能出现系统失效。当系统必须在进程的工作区外部 (在物理内存或分页文件中的其他位置) 查找信息时,就会出现页面错误。当系统缺乏存储资源 (物理内存及虚拟内存) 来满足使用需求,从而遇到过多的分页时,就会出现系统失效。系统将花更多的时间来分页而不是执行应用程序。当系统失效时,Memory:Pages/see 计数器将持续高于每秒 100 页。系统失效严重降低了系统的性能。此外,动态扩展分页文件将导致碎片化。分页文件将散布在整个磁盘上而不是在启动时的连续空间中创建,从而增加了系统的开销,并导致系统性能降低。因此,应该尽量避免系统增加分页文件的大小。

设计步骤

(1)观察和调整 Windows XP/7 的内存性能。

步骤 1:阅读“背景知识”,请回答:

  1. 什么是“分页过程”?

  2. 什么是“内存共享”?

  3. 什么是“未分页合并内存”和“分页合并内存”?

Windows xp 中,未分页合并内存的最大限制是多少?

  1. Windows xp 分页文件默认设置的最小容量和最大容量是多少?

步骤 2:登录进入 Windows xp。

步骤 3:查看包含多个实例的应用程序的内存需求。

  1. 启动想要监视的应用程序,例如 Word。

  2. 右键单击任务栏以启动“任务管理器”。

  3. 在“Windows 任务管理器”对话框中选定“进程”选项卡。

  4. 向下滚动在系统上运行的进程列表,查找想要监视的应用程序。

请在表5-1中记录:

“内存使用”列显示了该应用程序的一个实例正在使用的内存数量。

  1. 启动应用程序的另一个实例并观察它的内存需求。

请描述使用第二个实例占用的内存与使用第一个实例时的内存对比情况。

步骤 4:未分页合并内存。

估算未分页合并内存大小的最简单方法是使用“任务管理器”。未分页合并内存的估计值显示在“任务管理器”的“性能”选项卡的“核心内存”部分。见5.4

还可以使用“任务管理器”查看一个独立进程正在使用的未分页合并内存数量和分页合并内存数量。操作步骤如下:

  1. 单击“Windows 任务管理器”的“进程”选项卡,然后从“查看”菜单中选择“选择列”命令,显示“进程”选项卡的可查看选项。

  2. 在“选择列”对话框中,选定“页面缓冲池”选项和“非页面缓冲池”选项旁边的复选框,然后单击“确定”按钮。

返回 Windows Xp“任务管理器”的“进程”选项卡时,将看到其中增加显示了各个进程占用的分页合并内存数量和未分页合并内存数量。

仍以刚才打开观察的应用程序 (例如 Word) 为例,请在表5-2中记录:

从性能的角度来看,未分页合并内存越多,可以加载到这个空间的数据就越多。拥有的物理内存越多,未分页合并内存就越多。但未分页合并内存被限制为 256MB,因此添加超出这个限制的内存对未分页合并内存没有影响。

步骤 5:提高分页性能。

在 Windows xp 的安装过程中,将使用连续的磁盘空间自动创建分页文件(pagefile.sys) 。用户可以事先监视变化的内存需求并正确配置分页文件,使得当系统必须借助于分页时的性能达到最高。

虽然分页文件一般都放在系统分区的根目录下面,但这并不总是该文件的最佳位置。要想从分页获得最佳性能,应该首先检查系统的磁盘子系统的配置,以了解它是否有多个物理硬盘驱动器。

  1. 在“开始”菜单中单击“设置” – “控制面板”命令,双击“管理工具”图标,再双击“计算机管理”图标。

  2. 在“计算机管理”窗口的左格选择“磁盘管理”管理单元来查看系统的磁盘配置。

请在表5-3中记录:

如果系统只有一个硬盘,那么建议应该尽可能为系统配置额外的驱动器。这是因为:Windows

xp 最多可以支持在多个驱动器上分布的 16 个独立的分页文件。为系统配置多个分页文件可以实现对不同磁盘 I/O 请求的并行处理,这将大大提高 I/O 请求的分页文件性能。

步骤 6:计算分页文件的大小。

要想更改分页文件的位置或大小配置参数,可按以下步骤进行:

  1. 右键单击桌面上的“我的电脑” (Win7 为计算机)图标并选定“属性” (Win7 为高级系统设置) 。

  2. 在“高级”选项卡上单击“性能选项”按钮。

  3. 单击对话框中的“虚拟内存”区域中的“更改”按钮。

请记录:见5.4

  1. 要想将另一个分页文件添加到现有配置,在“虚拟内存”对话框中选定一个还没有分页文件的驱动器,然后指定分页文件的初始值和最大值 (以兆字节表示) ,单击“设置”,然后单击“确定”。

  2. 要想更改现有分页文件的最大值和最小值,可选定分页文件所在的驱动器。然后指定分页文件的初始值和最大值,单击“设置”按钮,然后单击“确定”按钮。

  3. 在“性能选项”对话框中单击“确定”按钮。

  4. 单击“确定”按钮以关闭“系统特性”对话框。

(2)了解和检测进程的虚拟内存空间。

步骤 1:创建一个“Win32 Consol Application”工程,然后拷贝清单 5-1 中的程序,编译成

可执行文件。

步骤 2:在 VC 的工具栏单击“Execute Program”(执行程序) 按钮,或者按 Ctrl + F5 键,或者在“命令提示符”窗口运行步骤 1 中生成的可执行文件。

步骤 3:根据运行结果,回答下列问题。见5.4

按 committed、reserved、free 等三种虚拟地址空间分别记录实验数据。其中“描述”是指对该组数据的简单描述,例如,对下列一组数据:

00010000 – 00012000 <8.00KB> Committed, READWRITE, Private

可描述为:具有 READWRITE 权限的已调配私有内存区。

将系统当前的自由区 (free) 虚拟地址空间按表5-4格式记录。

将系统当前的已调配区 (committed) 虚拟地址空间按表5-5格式记录。

将系统当前的保留区 (reserved) 虚拟地址空间按表5-6格式记录。

详细设计

(1)了解和检测进程的虚拟内存空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// 工程 vmwalker
#include <windows.h>
#include <iostream>
#include <shlwapi.h>
#include <iomanip>
#pragma comment(lib, "Shlwapi.lib")
// 以可读方式对用户显示保护的辅助方法。
// 保护标记表示允许应用程序对内存进行访问的类型
// 以及操作系统强制访问的类型
inline bool TestSet(DWORD dwTarget, DWORD dwMask)
{
return ((dwTarget &dwMask) == dwMask) ;}
# define SHOWMASK(dwTarget, type) \
if (TestSet(dwTarget, PAGE_##type) ) \
{std :: cout << ", " << #type; }
void ShowProtection(DWORD dwTarget)
{
SHOWMASK(dwTarget, READONLY) ;
SHOWMASK(dwTarget, GUARD) ;
SHOWMASK(dwTarget, NOCACHE) ;
SHOWMASK(dwTarget, READWRITE) ;
SHOWMASK(dwTarget, WRITECOPY) ;
SHOWMASK(dwTarget, EXECUTE) ;
SHOWMASK(dwTarget, EXECUTE_READ) ;
SHOWMASK(dwTarget, EXECUTE_READWRITE) ;
SHOWMASK(dwTarget, EXECUTE_WRITECOPY) ;
SHOWMASK(dwTarget, NOACCESS) ;}
// 遍历整个虚拟内存并对用户显示其属性的工作程序的方法
void WalkVM(HANDLE hProcess)
{
// 首先,获得系统信息
SYSTEM_INFO si;
:: ZeroMemory(&si, sizeof(si) ) ;
:: GetSystemInfo(&si) ;
// 分配要存放信息的缓冲区
MEMORY_BASIC_INFORMATION mbi;
:: ZeroMemory(&mbi, sizeof(mbi) ) ;
// 循环整个应用程序地址空间
LPCVOID pBlock = (LPVOID) si.lpMinimumApplicationAddress;
while (pBlock < si.lpMaximumApplicationAddress)
{// 获得下一个虚拟内存块的信息
if (:: VirtualQueryEx(
hProcess, // 相关的进程
pBlock, // 开始位置
&mbi, // 缓冲区
sizeof(mbi))==sizeof(mbi) ) // 大小的确认
{// 计算块的结尾及其大小
LPCVOID pEnd = (PBYTE) pBlock + mbi.RegionSize;
TCHAR szSize[MAX_PATH];
:: StrFormatByteSize(mbi.RegionSize, szSize, MAX_PATH) ;
std :: cout.fill ('0') ;
std :: cout<< std :: hex << std :: setw(8) << (DWORD) pBlock << "-"
<< std :: hex << std :: setw(8) << (DWORD) pEnd
<< (:: strlen(szSize)==7? " (" : " (") << szSize<< ") " ;
switch(mbi.State)
{
case MEM_COMMIT :
std :: cout << "Committed" ; break;
case MEM_FREE :
std :: cout << "Free" ; break;
case MEM_RESERVE :
std :: cout << "Reserved" ; break; }
if(mbi.Protect==0 && mbi.State!=MEM_FREE)
{
mbi.Protect=PAGE_READONLY; }
ShowProtection(mbi.Protect);
switch(mbi.Type)
{
case MEM_IMAGE :
std :: cout << ", Image" ; break;
case MEM_MAPPED:
std :: cout << ", Mapped"; break;
case MEM_PRIVATE :
std :: cout << ", Private" ; break;}
// 检验可执行的影像
TCHAR szFilename [MAX_PATH] ;
if (:: GetModuleFileName (
(HMODULE) pBlock, // 实际虚拟内存的模块句柄
szFilename, //完全指定的文件名称
MAX_PATH)>0) //实际使用的缓冲区大小
{
// 除去路径并显示
:: PathStripPath(szFilename) ;
std :: cout << ", Module: " << szFilename; }
std :: cout << std :: endl;
// 移动块指针以获得下一下个块
pBlock = pEnd; } } }
void ShowVirtualMemory()
{
// 首先,让我们获得系统信息
SYSTEM_INFO si;
:: ZeroMemory(&si, sizeof(si) ) ;
:: GetSystemInfo(&si) ;
// 使用外壳辅助程序对一些尺寸进行格式化
TCHAR szPageSize[MAX_PATH];
::StrFormatByteSize(si.dwPageSize, szPageSize, MAX_PATH) ;
26
DWORD dwMemSize = (DWORD)si.lpMaximumApplicationAddress -(DWORD) si.lpMinimumApplicationAddress;
TCHAR szMemSize [MAX_PATH] ;
:: StrFormatByteSize(dwMemSize, szMemSize, MAX_PATH) ;
// 将内存信息显示出来
std :: cout << "Virtual memory page size: " << szPageSize << std :: endl;
std :: cout.fill ('0') ;
std :: cout << "Minimum application address: 0x"<< std :: hex << std :: setw(8)
<< (DWORD) si.lpMinimumApplicationAddress<< std :: endl;
std :: cout << "Maximum application address: 0x"<< std :: hex << std :: setw(8)
<< (DWORD) si.lpMaximumApplicationAddress<< std :: endl;
std :: cout << "Total available virtual memory: "<< szMemSize << std :: endl ; }
void main()
{
//显示虚拟内存的基本信息
ShowVirtualMemory();
// 遍历当前进程的虚拟内存
::WalkVM(::GetCurrentProcess()); }

5.4实验结果和分析

(1)观察和调整 Windows XP/7 的内存性能。

步骤1**:**

  1. 分页过程:当 Windows 求助于硬盘以获得虚拟内存时,这个过程被称为分页。分页就是将信息从主内存移动到磁盘进行临时存储的过程。

  2. 内存共享:应用程序需要彼此通信和共享信息。

  3. 未分页合并内存:包含必须驻留在内存中的占用代码或数据。

分页合并内存:存储迟早需要的可分页代码或数据的内存部分。

Windows xp 中,未分页合并内存的最大限制是:256MB (在 Windows NT 4 中的限制为 128MB)

4) Windows xp 使用内存容量的1.5倍作为分页文件的最小容量,这个最小容量的两倍作为最大容量。

步骤3**:**

表5-1 应用内存需求实验记录

映像名称 PID CPU 时间 内存使用
Chrome 11704 00 0:01:07 10,844k

步骤4**:**

​ 总数 :248MB 分页数:179MB 未分页 :69MB

表5-2 应用内存使用实验记录

映像名称 PID 内存使用 页面缓冲池 非页面缓冲池
Chrome 11704 00 399k 10k

步骤5**:**

表5-3 磁盘配置实验记录

布局 类型 文件系统 容量 状态
(C:) 简单 基本 NTFS 80.00GB 状态良好(系统,启动,页面文件,活动,故障转储,主分区)
(D:) 简单 基本 NTFS 15.00GB 良好(逻辑驱动器)
(E:) 简单 基本 NTFS 15.00GB 良好(逻辑驱动器)
(F:) 简单 基本 FAT32 49.99GB 良好(逻辑驱动器)

所选驱动器的页面文件大小:

1_驱动器:C: 可用空间:55653MB 初始大小(MB):无 最大值(MB):无

2_驱动器:D: 可用空间:14611MB 初始大小(MB):无 最大值(MB):无

3_驱动器:E: 可用空间:15260MB 初始大小(MB):无 最大值(MB):无

4_驱动器:F: 可用空间:14110MB 初始大小(MB):无 最大值(MB):无

5_所有驱动器页面文件大小的总数:

允许的最小值:16MB 推荐:5266MB 当前已分配:3511MB

(2)了解和检测进程的虚拟内存空间。

步骤3**:**

虚拟内存每页容量为:4.00KB 最小应用地址:0x00010000

最大应用地址:0x7ffeffff 当前可供应用程序使用的内存空间为:1.99GB

当前计算机的实际内存大小为:4.00GB

理论上每个 Windows 应用程序可以独占的最大存储空间是:4.00GB

表5-4 自由区虚拟地址空间实验记录

地址 大小 虚拟地址空间类型 访问权限 描述
00134000-00140000 48.0KB Free NOACCESS 具有NOACCESS权限的内存区
00141000-00150000 60.0KB Free NOACCESS 具有NOACCESS权限的内存区
001b7000-001c0000 36.0KB Free NOACCESS 具有NOACCESS权限的内存区
00388000-00390000 32.0KB Free NOACCESS 具有NOACCESS权限的内存区
00391000-003a0000 60.0KB Free NOACCESS 具有NOACCESS权限的内存区
003a1000-003b0000 60.0KB Free NOACCESS 具有NOACCESS权限的内存区
003b7000-003c0000 36.0KB Free NOACCESS 具有NOACCESS权限的内存区
003c2000-00400000 248KB Free NOACCESS 具有NOACCESS权限的内存区
00485000-00520000 620KB Free NOACCESS 具有NOACCESS权限的内存区
00631000-00640000 60.0KB Free NOACCESS 具有NOACCESS权限的内存区
01240000-01310000 832KB Free NOACCESS 具有NOACCESS权限的内存区
01717000-73f10000 1.78GB Free NOACCESS 具有NOACCESS权限的内存区
770d7000-77130000 356KB Free NOACCESS 具有NOACCESS权限的内存区
77131000-7f6f0000 133MB Free NOACCESS 具有NOACCESS权限的内存区
7f7f0000-7ffa0000 7.68MB Free NOACCESS 具有NOACCESS权限的内存区
7ffd3000-7ffd7000 16.0KB Free NOACCESS 具有NOACCESS权限的内存区
7ffd8000-7ffdf000 28.0KB Free NOACCESS 具有NOACCESS权限的内存区

表5-5已调配区虚拟地址空间实验记录

地址 大小 虚拟地址空间类型 访问权限 描述
00010000-00020000 64.0KB Committed READWRITE 具有READWRITE权限的已调配Mapped内存区
00020000-00030000 64.0KB Committed READWRITE 具有READWRITE权限的已调配Mapped内存区
0012d000-0012e000 4.00KB Committed READWRITE 具有READWRITE权限的已调配私有内存区
0012e000-00130000 8.00KB Committed READWRITE 具有READWRITE权限的已调配Image内存区
00130000-00134000 16.0KB Committed READWRITE 具有READWRITE权限的已调配私有内存区

表5-6保留区虚拟地址空间实验记录

地址 大小 虚拟地址空间类型 访问权限 描述
00030000-0012d000 0.98MB Reserved READONLY 具有READONLY权限的已调配私有内存区
001c7000-00280000 740KB Reserved READONLY 具有READONLY权限的已调配私有内存区
00283000-00288000 20KB Reserved READONLY 具有READONLY权限的已调配私有内存区
00333000-00340000 52KB Reserved READONLY 具有READONLY权限的已调配Mapped内存区
0065f000-00740000 900KB Reserved READONLY 具有READONLY权限的已调配Mapped内存区