http://www.yythac.com/ar/ljjc2.txt
来源:黑盟
现在我们正通过性能监视器的显示区域观察由系统中每一个进程产生的IO操作。针对每个进程存
在两条折线。其中的一条用于记录数据操作,另一条用于记录像文件打开和关闭之类的其他操作。很快,
系统像我们想象的那样平静下来。现在,让我们回到命令行状态并启动一些将导致许多操作的活动。让我
们来看看一个涉及硬盘上全部目录的操作——dir c:/s。这将意味着从C盘根目录开始产生一个自上而下遍
历C盘上所有子目录的目录列表。像我们看到的这样,为了显示所需数据正在执行许多目录读取操作。在该
操作执行过程中,让我们回到性能监视器,并将其显示内容顶部的折线看作是有某人正在执行大量IO操作
。好了,现在请考虑如何确定这条代表大量IO操作的折线实际所映射的进程。
让我们打开加亮显示功能。单击加亮按钮或使用快捷键Ctrl-H 。如果你以前曾经使用过性能监视器,那你
一定知道打开加亮功能后,当通过键盘上的下箭头滚动列表中的计数器时,当前在列表框中选中的进程或折
线将被加亮显示为白色。因此,我将向下滚动计数器直至当前在顶部的折线变为白色。就是这样。你们能够
看到底部显示的实例名称吗?正是CMD。因此,进程CMD便是产生所有这些IO操作的那个进程。这很容易理解
,因为CMD就在这儿。它就是命令行窗口并且正是它产生了涉及目录的IO操作。你可以看到这有多快,使用
性能监视器,监视每一个进程每秒内执行的IO操作并且快速定位某个IO操作由哪个进程负责。好了,这很有
趣,但也产生了一个问题,即IO操作的去向是哪里?刚刚介绍的内容仅告诉了我们IO操作的发生。它将把我
们带入幻灯片上的下
一个工具——文件监视器。
文件监视器(File Mon)是迄今为止我们使用的第三个来源于sysinternals.com网站的工具。像我们前面用
过的工具一样,它涉及到一个设备驱动程序的使用。当我们运行文件监视器时,它所做的工作是加载一个可
以截取系统中每个IO操作的文件系统驱动程序,将每个IO操作显示在屏幕上,之后再将其送往相应的设备驱
动程序。因此它在很大程度上降低了IO操作的速度,但是它确实提供了一种有效的方式用以确定IO操作的来
源,因为每个IO操作都将被它记录,所记录的信息包括进程名称、所引用的文件名称以及操作的类型——读
或些。下面让我们来具体地看一看它。回到命令行状态,从演示目录下通过filemon命令运行文件监视器。现
在文件监视器启动了对文件的监视活动。尽管看上去好像有一些IO操作正在后台运行,系统还是马上平静下
来,事实上,在
这个特殊的Windows 2000系统中存在一个系统进程,它每隔1或2秒执行一些访问数据库的IO操作。现在,让
我们回到命令行状态并试着模仿一些针对某个特定文件的繁重的IO活动。这个特定目标文件是每个Windows
2000系统都拥有的一个大文件,即驱动程序压缩包文件。
这个驱动程序压缩包文件包含随Windows 2000一同发布的所有设备驱动程序的压缩版本。它存放在Win NT D
river cache文件夹中。我将启动Window NT资源管理器并进入到我的Win NT Driveracche文件夹中对这个文
件进行一个简单的拷贝操作。我打开C驱动器,展开WinNT目录,接着展开Driver cache目录以及其中的I386
目录,这里存放着driver.cab文件。请注意它的大小是51兆。因此它将是一个理想的测试对象。我将仅仅通
过编辑菜单中的拷贝命令和粘贴命令进行一个简单的文件拷贝。你可以看到我们现在正在拷贝一个51兆的文
件。
让我们回到文件监视器并观察一下它的显示内容。好的,像我们在输出区域中看到的那样,我们可以观察到
大量对driver.cab文件及其备份的IO操作。我使用快捷键Ctrl-E以终止文件监视器的监视活动,同时我们可
以看到一些读写操作——从driver.cab文件进行的读操作以及对其同名拷贝进行的写操作。现在让我们返回
并取消文件拷贝,你将看到一个使用文件监视器观察独立的IO操作并且使你能够查看IO操作发生在哪个文件
中的例子。
你可以用文件监视器完成一些过滤工作。例如,如果你只对C或D驱动器或是这些驱动器上一个特殊目录中的
IO操作感兴趣,你可以对其特定的路径进行过滤,你也可以加亮显示一个指定的路径名以便使你能够轻松地
找到所有被监视的文件中你所感兴趣的特殊文件。由此再次验证了,对于观察IO活动以及跟踪IO操作发生在
哪个文件上,文件监视器是一个重要的工具。
这一部分的最后一点是文件监视器可以通过在一行中加入一个小星号来指出分页IO操作。由于Windows 2000
高速缓存管理器使用通常的分页机制和内存管理器来完成文件IO操作,你可以看到发生在由应用程序打开的
文件中的分页活动。换言之,由于高速缓存子系统通过通常的分页机制使用内存管理器从文件中读取数据,
对于一个打开和读取文件的应用程序,其IO操作自身在文件监视器中显示为分页读操作。
文件或系统进程活动的最后一个领域,也是同样重要以至要求能够监视的内容是注册活动。如你们中大多数
人知道的那样,注册表是NT用于对其自身进行配置的数据库,需要装载的驱动程序、所有的管理设置以及每
个用户档案的设置均存放在这里。有时,对于一个系统管理员来说,知道某个特定设置被存储在注册表中的
什么位置是很有帮助的。在sysinternals.com网站上有一个称为注册表监视器的工具可以用来监视对注册表
的每一次读和(或)写。让我们来运行注册表监视器。我将回到命令行状态并从演示目录中运行从sysinter
nals.com网站得到的注册表监视器的一个拷贝。当注册表监视器启动后,它将装载一个驱动程序以便开始截
取所有对注册表的查询。此刻,作为性能监视器容器的MMC进程也正在进行一些常规的注册表查询。因此,
让我们返回并关闭
性能监视器以使这些查询工作停止。好,现在系统平静下来了。注册表通常是平静的。换言之,如果一个进
程正在执行常规的注册表读或写操作,此时出现了错误,你可能会考虑为厂商整理一份错误报告。在进程或
NT启动时,注册表将会被查询。它并不是个会被经常访问的数据库。使用注册表监视器可以在寻找特定系统
设置在注册表中存储位置时最大限度的得到启发。例如,如果你启动注册表监视器后进入控制面板,访问一
些设置程序或选项卡,你将能够看到在控制面板中所涉及的设置信息在注册表中所处位置的精确跟踪信息,
并且它可能引导对注册表的一些更深的研究,从而作为Windows 2000资源工具包帮助文件(该文件记录了绝
大多数注册表键)的辅助。这便是注册表监视器实用工具。接下来提两个问题。NT中运行什么?调度的单元
是什么?答案是线程。请记住,进程并不运行,线程才能运行。每个进程至少包含一个线程。
线程如何表现得看起来运行了许多,但却并未占用CPU时间呢?一个线程拥有大量与上下文无关的内容,它
们使线程可被NT选中运行,但却很少占用或根本不占用CPU时间。答案是:NT使用一个基于间隔的时钟定时
器机制来计算CPU时间。如果时钟激发时曾经处于运行状态的线程已不再运行,它将不占用时钟周期。作为
缺省时钟间隔,每10毫秒——尽管不同系统的缺省值不同,无论哪个线程是当前线程,它都将被认为占用了
这10毫秒的周期。如果没有线程在运行,将被计为被空闲线程占用。空闲线程是任务管理器中所显示的系统
空闲进程的一部分。让我们回忆一下,在进程选项卡列表中所列出的第一个进程便是空闲进程。这个进程的
作用是:在没有线程运行时,累计并占用所有CPU时钟周期。
最后一个问题。进程地址空间的大小是多少?NT是一个32位操作系统,32位对应于4GB。缺省情况下,NT将地
址空间的一半分给用户进程,并将4GB的另一半留给自己使用。
我们已经花费了一些时间来观察内部进程以及这些进程内部的IO活动、动态链接库使用情况、打开的句柄、
注册表活动。在下面一节中,我们将更清楚地了解NT如何区分操作系统工作占用的CPU时间和应用程序占用
的CPU时间,以及NT如何维护和计算中断时间。之所以中断处理是一个非常重要的主题,是因为它不占用任
何线程,因而不被显示在任何进程中。换言之,一个拥有繁重中断负荷的系统看起来可能很慢,然而却好像
没有进程在运行。我们将在这一节中回答这个问题。现在,我建议我们最好回过头来讨论花费在操作系统应
用中的时间和花费在应用程序代码自身中的时间的界限。NT使用两种内存保护态,它们有时被称为核心态和
用户态,或在另外一些场合被称为特权态和用户态。一个进程4GB地址空间中的每一页均被标记出它是否是
处于核心态的页。所
有系统地址空间中的页均被标记为核心页。所有用户地址空间中的页均被标记位用户页。访问被标记为核心
页的页面的唯一途径是运行在核心态,并且只有操作系统和设备驱动程序才能运行在核心态。换言之,除非
通过加载设备驱动程序,否则一个用户程序将不能使自己运行在核心态中。这就是在应用程序和操作系统之
间提供的内存保护的坚固级别。无论一个应用程序的运行多么不遵循规则,无论它试图引用和改变什么内存
地址,它都绝对不会破坏系统数据结构,这是因为所有的操作系统和设备驱动程序内存结构都被标记为核心
页。他们处于系统地址空间,同时,因为应用程序运行在用户态,它不可能看到或修改这些数据。
线程经常在用户态和核心态之间进行切换。线程每进行一次系统调用,例如打开一个文件、关闭一个文件、
读取数据、写入数据,它便从用户态的应用程序代码变为核心态或操作系统代码。当10毫秒的时钟间隔再次
被激发时,NT将如何决定怎样占用CPU时间呢?如果线程正处在核心态或正在运行操作系统的一部分,它将为
线程增加特权时间计数器值。然而,如果线程正运行在用户态或应用程序内部,它将使线程占用用户时间。
因此,NT精确的跟踪一个线程花费在应用程序中以及花费在操作系统中的时间量。观察任务管理器进程选项
卡中的CPU时间列会发现,它并未区分特权时间和用户时间,而仅仅显示了全部CPU时间,但是有一些工具允
许我们观察应用程序并迅速计算出这个应用程序分别在程序自身和操作系统中花费了多少时间。它将我们带
入了下一个演示:
使用Qslice或Quick Slice工具检测进程CPU时间。
让我们通过开始/运行/Qslice运行Quick Slice。它包含在Windows 2000支持工具中。Quick Slice中显示的
是进程的CPU活动,其中红色指示为核心态、蓝色指示为用户态。现在请注意在我的系统上发生了什么?Qui
ck Slice中称为系统进程的0号进程内部100%处于核心态,但在任务管理器中0号进程却被称为系统空闲进程
。你可以看到NT进程显示工具中的一个怪癖,对于空闲进程,每个工具创造它们自己的名称并且这些名称并
不一致。空闲进程是NT用于统计空闲CPU循环的假冒进程,并且这些CPU循环被计为核心态时间。
让我们运行一个程序来模拟一个通常的用户应用程序。这是一个称作CPUstress的程序,它包含在资源工具
包中。我将通过开始/运行/CPUstress运行该程序。当其开始运行后,缺省的,它将拥有一个运行在低活动
级上的线程。低活动级意味着它有25%的时间处于运行状态而另75%的时间处于等待状态。在底部的CPUstre
ss程序时常突然出现并在用户态运行一小段时间——表现为蓝色条状图,之后重新变为等待。让我们把它
的活动级别变为最大。
单击活动列表框,向下滚动并选择最大。现在请注意发生了什么。变成了100%蓝色。最大活动级别使CPUstr
ess陷入了一个无限循环。这里仅有一个进程,因此,它基本上已陷入到应用程序中。且并未产生任何系统
调用。如果针对一个进程,我看到一组分开的蓝色和红色,这说明这个程序处于一种通常的情况,即一部分
时间花费在应用程序中、一部分时间花费在操作系统中。同样,使用Qslice也可以相当容易地观察一个进程
并迅速确定进程的时间如何被消耗——是处于用户态应用程序中还是处于核心态操作系统内部。
基于以下三种原因之一,NT会在核心态或特权态下运行操作系统代码,我们将仅描述其中的第一种情况,
即用户应用程序发出一个系统调用请求——如打开一个文件、关闭一个文件并释放为其分配的内存、释放内
存、创建一个进程、创建一个线程等等。我们还将介绍第二种情况并在下一节中介绍第三种情况。
换言之,NT在核心态花费时间的第二个原因是由于中断调用使用户程序不能继续运行。中断调用是用户应用
程序发出IO请求所造成的。在接下来的几张幻灯片中我们将会看到一些技术细节,似乎只有NT设备驱动程序
的编写者会对这些内容感兴趣,促使我们深入到这一层次细节的原因是NT计算中断调用时间的方式,通过性
能监视器中两个分开的计数器——一个用于统计中断调用时间的计数器和另一个称为DPC时间百分比的计数
器——可以显示中断调用时间。那么,DPC是什么呢?为了理解这两个计数器,首先我们需要理解DPC。首先
让我们来看一看当一个中断调用产生时将会发生什么。当中断调用产生时,正在运行的线程将被依次中断。
一段NT系统代码将会被运行,以便找到拥有这个中断源的驱动程序,并调用该驱动程序,该驱动程序完成需
要由它完成的
工作后,释放中断并返回到正在执行的线程。仅作为一个侧面,由于中断产生时是与上下文无关的,在通用
操作系统及处理中断调用方面,NT被认为是完美快捷的。NT并不切换到某些特殊的中断处理线程。它仅仅保
存当前运行线程的状态,并调用驱动程序来完成工作,之后中断被释放,被中断的线程重新回到运行状态。
由于中断调用可能来源于许多不同的中断源,必须使用一种机制来实现中断的优先提交,这也正是使用两个
不同的计数器——中断调用时间和DPC时间——来监视中断的原因。NT使用32个相关优先级来实现中断的优先
提交和服务。它是一个你永远不会在用户程序中看到的内部编号,同样,你也永远不会在性能监视器中看到
它。它被称为中断请求优先级或IRQL。
当一个驱动程序被加载时,它告诉NT自己的中断源和IRQL。请考虑一下。换言之,中断拥有一个相关的优先
权。因此,当一个中断产生时,NT必须查看该中断源的IRQL。如果它的值高于现在正在运行的程序所处的优
先级,那么该中断将得到服务。如果它的值低于或等于现在正在运行的程序所处的优先级,对该中断的处理
将被延迟到高优先级中断源完成工作之后。当一个中断产生时,什么将被阻挡?什么工作将不能在驱动程序
处理中断的过程中发生呢?答案是:其它具有相同或较低优先级的中断以及所有线程的执行。换言之,因为
中断调用总是中断进程活动而无论其具有何等的进程或线程优先级,因此系统中所有的进程活动都将被挂起
。为了使具有高优先级的驱动程序所占用的时间达到最少,NT提供了这样一种方法:驱动程序好像是在说,
我做了应当在这个中断优先级下进行的工作,但是我还有更多工作要做。现在我将释放中断,但请在稍后再
次调用我,以便使我能够完成在高优先级下未能做完的工作。这种操作被称为延迟分配调用(DPC)。延迟分
配调用是驱动程序请求NT稍后再次调用它的一种方法。系统中存在一个用于记录驱动程序回调请求的系统队
列或列表。何时进行回调呢?当没有更高优先级的中断调用需要提交时。请看最后一张幻灯并注意DPC(延
迟分配调用)落入优先级谱系中的什么位置?他们落入优先级2,该优先级低于硬件设备中断但高于常规线
程执行。
一种简单的方法是把中断调用看作两个阶段:第一个阶段处于中断级别,第二个阶段处于DPC级别。在性能
监视器中,DPC和中断调用时间这两个计数器就在你的面前,因为他们就在处理器的缺省CPU时间计数器当中
,这就是我们解释中断提交过程细节的原因,由此,你可以更清楚地理解中断调用时间和DPC时间所代表的
内容。中断调用时间反映了中断过程的第一阶段。DPC时间反映了中断过程的第二阶段。现在,让我们做一
个演示并观察性能监视器中的中断活动。
启动性能监视器。让我们通过单击添加按钮向显示区域中添加中断调用时间和DPC时间。显示区域中出现了
我们刚刚描述的计数器。单击添加。单击关闭。由于性能监视器的缺省刻度范围是0到100,这里只显示了一
些相当小的数字。我将通过单击鼠标右键打开属性对话框,并切换到图表选项卡,将垂直显示的最大值由
100减至10以便易于读取数值。让我们来做一下,现在,我们正通过DPC活动观察中断。红线代表DPC时间,
绿线代表中断调用时间。如果我们快速地来回移动鼠标,象我正在做的这样,注意到绿线出现一些突然的
跃升了吗?它是由移动鼠标产生的中断形成的。现在,DPC时间好像在每秒有规律地发生,这肯定是某些IO
操作的结果。如果见到这种有连续DPC操作不断发生的系统,我们应返回到前面的内容。我们的下一步工作
是找出谁正在执行IO操作。
你还记得完成这个工作的工具吗?正是文件监视器。文件监视器将告诉我们哪个进程产生了稍后将导致DPC
的IO操作。在观察中断调用时间活动时需要记住的重点是它不会占用任何线程或进程,这将引出我们这一节
的快速问答。
如果系统看上去很慢,但在任务管理器中却并未看到有进程正在运行,正在发生什么呢?一定是中断调用。
使用性能监视器查看每秒的中断数和每秒的DPC数或中断调用时间百分比和DPC时间百分比。再次强调,中断
调用中消耗的时间并不占用线程,因此,没有进程处于运行状态。请观察中断调用时间。
我说过我们将回过头来标识由NT创建并运行于系统中的每个进程,为什么这很重要呢?因为如果某些上下文
正在运行且不是由你所运行的,那么它一定是NT的一部分——某些系统进程。因此,能够标识出所有的系统
进程是在Windows 2000和Windows NT 4.0系统中进行故障诊断或性能分析的另一个重要组成。
现在,我们用来观察系统进程树的工具是在前面曾将介绍过的Tlist/t。同样,Tlist/t将显示进程间的层次
结构。因此,使用该工具,我们可以对进程来源以及进程在树中所处位置进行快速浏览。作为对那一节的回
顾,我将返回命令行方式,执行Tlist/t,并在回顾幻灯时参考这些内容。请观察Tlist/t的输出,系统中的
头两个进程正是我们将要描述的——它们的进程ID是0和8。0号进程是空闲进程。在多处理器系统中,这个不
运行实际程序的进程将为每个CPU分配一个线程。换言之,每个CPU的空闲时间将被分别计算。顺便提一下,
这也是检查你系统中第二、三、四、五个CPU使用效率的一种快速简洁的方法。通过分别观察每个CPU的空闲
时间,可以确定在你的多处理器服务器或工作站中负载分布的均匀程度。空闲进程并不显示为运行。请记住
,在Quick Slice及任务管理器中,空闲进程看起来在被运行,这是因为当时钟间隔时间激发时,没有线程
正在运行,因而时钟间隔被CPU的空闲线程所占用。因此使其看起来像是在运行,但实际上,系统正处于空
闲状态。
第二个进程——8号进程(在NT 4.0中的进程ID为2),是一类称为核心态系统线程的特殊类型线程家族。这
个被称作系统的系统进程,包含了两个版本NT系统中操作系统和一些需要使其自身部分运行于实际线程的设
备的子例程实例。换言之,它们需要与其它一些系统活动并发执行。一些例子可以帮助理解这个概念。
操作系统中几个需要在后台运行的部分——例如交换程序——会运行一个系统线程。当NT认为一个在一段时
间内未运行的进程变为空闲时,若其它进程请求物理内存,它将把该进程的内存空间标记为被清除。那么,
由谁来完成将该进程交换出内存的工作呢?正是交换程序。交换程序是与其它在系统中运行的线程同时运行
着的一个线程。文件服务器是创建系统线程的一个驱动程序。这是一个有趣的例证,在负荷较重的文件服务
器上,作为客户端IO活动的结果而表现为运行状态的进程却由于该文件服务器本身不是一个进程而不表现为
一个服务器进程。要知道,是驱动程序创建和使用系统线程以提供伺服并为远程网络IO请求服务。因此,这
是一个非常重要的监视点,在此,负荷较重的文件服务器将使系统线程得以继续,而因为系统线程主要在被
称作系统的进程中予以披露,故我们需要一些方法来深入而密切地关注系统进程,从而找出到底是什么线程
正在运行着。基于我们已经讲到的内容,如果告诉你系统进程正在运行着,那你又能知道些什么呢?基本来
说,你什么也知道不了。你只知道NT中的某一片段(或许是一个驱动程序)正在运行,但你并不知道它具体
是哪一个片段。这就将我们带到了下一个演示中:理解系统进程中的哪个线程正在运行,进而知道NT中的哪
个驱动程序或片段创建了该线程。而这却是一个凌乱的处理过程,因为,它需要使用3个工具:性能监视器、
进程浏览器和NT 4.0资源工具包中一个被称为Pstat的工具,该工具并不只存在于Windows2000资源工具包中
,它也是Platform SDK(亦即平台软件开发工具包)的组成部分,且与MSDN(Microsoft开发网络)及其后
续版本一并发布。它也是本次讲座演示文件的组成部分。我们首先要做的是使用性能监视器找出运行于系统
进程中的线程。接着,我们将使用Pviewer来赋予它们那些我们所感兴趣的线程并找到线程的内存起始地址
,内存起始地址是一个代表该系统线程从系统沙箱中何处开始运行的数字。最后,我们将使用Pstat,该工
具提供了一个关于系统沙箱的内存映射并就线程运行于哪个驱动程序中进行定位,换言之,线程所运行的
代码片段是属于哪个驱动程序的。因此,该过程多少有些复杂,它毕竟使用了3个工具,但还是让我们进行
这个演示来看一看它是如何工作的。
首先,我们将回到性能监视器。让我们从一个新图表开始。事实上,由于我们已改变了图表设置,我们将启
动一个新的性能监视器实例。我将单击加号,并向图表中添加系统进程中线程的CPU时间。我转到线程对象,
选中处理器时间百分比,向下滚动到被称作系统的进程,单击第一个线程——线程0,拖曳鼠标,向下滚动直
到将所有系统进程中的线程全部被选中,然后,单击添加。现在,我并没能如愿,因为,在Windows 2000中
仍有另一个进程,该进程中也包含着一些系统线程,它就是CSR访问——一个Windows子系统进程。该进程是
包含部分Windows系统的NT片段。在NT 4.0中,所有的系统线程均存在于系统进程中。在Windows 2000中,某
些系统线程存在于CSR访问进程中,而另一些则存在于被称为系统的进程中。我们单击添加,接着,单击关
闭。
我现在查看30多个零散系统线程的执行情况。让我们快速移动鼠标,可以看到有东西曾运行过。我是如何在
这个由30多个零散计数器组成的列表中找到线程随机内存排列的呢?我将再次打开加亮开关,单击高亮度按
钮,向下滚动屏幕直到随鼠标移动而移动的计数器也被以白色加亮。在显示区域中部有一个绿色凸起。就在
那儿,你们看到了吗?是从绿色变成白色的那个。当我移动鼠标时,在CSR访问中的6号线程看上去正在运行
。第二步是使用Pviewer,该工具存在于支持工具包中,依次单击开始/程序/ Windows 2000支持工具/工具进
程浏览器。选中CSR访问,向下滚动并选中6号线程,我们现在所寻找的信息是线程的起始地址,它位于Pvie
wer显示区域的底部。该地址是线程开始执行的起点。它以十六进制显示,0X在十六进制中代表A000-9CBF。
好的,我们有了一个内存地址。接下来做什么呢?第三步——运行PStat,该工具存在于我们的演示中并在执
行着的PStat尾部。因此,请忽略掉出自线程的所有细节。在PStat显示区域的最后部分是系统沙箱的内存映
射。它列出了每个驱动程序的名字以及在系统内存中的地址。如果我让它到达末端并从后向前看,我将寻找
在线程运行地址处启动的驱动程序。不幸的是,PStat并不显示驱动程序的结束地址,而只提供起始地址。因
此,需要密切关注我们所查看的特定地址编号究竟落在了哪个驱动程序上。我们目前所举的例子非常简单,
因为这里只有一个驱动程序在A00处被调用。如果你查看整个列表,其它任何事件均编有以F、8或B打头的号
码。因此,我立刻就能判断出该线程设备肯定是驱动程序Win32K.SYS中的一个代码片段。它是Win32图形和
窗口操作系统的一个组件。这就有点儿意思了。当你移动鼠标时,你会期望窗口操作系统中的某一片段能够
运行以指示出你正在哪个窗口上移动着鼠标。虽然这只是一个人为例证,但它毕竟演示了使用上述3个工具(
性能监视器、Pviewer和PStat)以深入探究系统进程或CSR访问并找出创建线程的驱动程序的技巧。这是一
个非常重要的技巧,因为,如果系统进程运行在Windows 2000上,则在不找出线程归属于哪个驱动程序或系
统片段的情况下,你将无法对现行状况做出任何判断。如果线程起始地址碰巧落在操作系统映像(NToss (?)
kernel.exe)范围内的话,问题就可能有些复杂了。那么,你又能知道什么呢?你什么都知道不了。例如,
我们来查看一下PStat输出。最靠前的设备驱动程序——它并不是一个真正的驱动程序,而只是操作系统自
身——被在80400000处调用。如果我回到Pviewer并选中
系统进程——请注意,不是CSR访问,而是系统,则该进程中的若干线程均从地址804附近启动。于是,我单
击系统,请注意,当我向下滚动第一套线程时,多数线程的起始地址都在804附近。那么,这又告诉了我们
什么呢?它告诉了我们该线程是NT的一个片段,但并未指明是NT的哪个片段,但有一点可以肯定,该线程是
一个NT片段,而非一个驱动程序。如果你还想再往前走一步的话,这里有一个方法能将内存地址转化为子例
程的名字,即通过将操作系统内核映像标识表格(或调试标识)进行转储的方式来实现,该方法由Windows
2000用户诊测CD提供。这需要使用一个叫做内核调试器的工具,不过,我将不在本次讲座中予以演示,但如
果你想了解执行这一附加步骤的方法,就请阅读Windows NT第二版(该书在Microsoft出版社网站上免费提
供)第二章中关于如何转储Ntoss内核标识并追踪系统线程地址以得到操作系统子例程名称的有关详细内容
。现在,让我们回过头来完成剩下的系统进程树。请记住,TList/t为我们显示了这个树结构。这张幻灯片
恰恰以图形方式展示了进程间的父子关系。接下来,让我们完成对剩余进程的描述。如果你查看TList/t输
出,会注意到第一个以.EXE结尾的进程是SMSS,它代表会话管理器。这是第一个被创建的进程,并与系统剩
余部分的装载有关。为了让你们能够查看TList/t的输出,我将返回到命令行方式,并键入TList/t。该会
话管理器有两个孩子,即CSR和Winlogin。我们刚刚提及的CSR是窗口操作系统的一个片段,当你看到下一
张幻灯片时,会发现有两条关于为什么运行该进程的附加详细说明。CSR并不是一个频繁运行的进程,它仅
为小部分窗口系统请求而调用。如果你的系统中经常运行CSR访问进程,则可能存在一或两个原因,这也是
本子项目中的最后两部分——对字符应用程序(如命令行方式)进行的窗口管理和运行在终端窗口中的应
用程序。上述应用程序由CSR访问来处理。如果你运行16位的DOS或Windows 3.1应用程序,对该程序的某些
支持则包括在CSR访问中,但是,在常规的NT服务器或Windows 2000 Professional桌面系统中,该进程应是
静止的。现在,让我们返回上一张幻灯片并完成剩余的进程树。
顾名思义,Winlogon是一个登录进程。该进程提供了登录所需的类型控制和输入口令所需的对话框。当你输
入用户名和口令时,Winlogon将其发送给一个叫做LSASS的子进程。如果你执行对服务器或工作站的本地登
录,LSASS进程将在安全数据库(亦即SAM)中查对有关用户名和口令。由于网络登录服务运行在LSASS子进
程内,故如果你正在登录NT 4.0的域帐户,Winlogon会将用户名和口令发送给运行在域控制器上的LSASS子
进程,而上述域控制器则存在于包含着你正在登录的帐号的域中。
现在,让我们回来看TList/t的输出。在显示区域中,我们能看到Winlogon的多少个子进程呢?两个,即服
务控制器和LSASS。让我们谈一谈服务控制器。什么是Windows NT服务呢?一项服务就是服务器应用程序的
一个片段,该应用程序通常被安装在注册表中、并将在系统引导时被服务控制器启动。如果我们转到下一张
幻灯片,将会看到一张关于服务进程层次结构的图片。在一项服务被诸如SQL server或extreme server等服
务器应用程序添加至注册表中的情况下,当系统引导时,服务控制器将在注册表服务数据库中进行搜索,并
创建一个从属图表(因为服务项目之间能够彼此依靠),进而以正确的顺序启动它们。如TList/t输出所示,
服务控制器有许多子进程,这些子进程则代表了可执行程序的映像,而这些可执行程序映像又包含着运行服
务功能的服务器应用程序组件。现在,你将如何查看关于已安装服务的列表呢?我们依次单击开始/设置/控
制面板,并点击Windows 2000中的管理工具,在管理工具中,我们单击服务。目前得到的显示与你从Window
s NT 4.0中获得的较为相似,并伴有一些附带信息。例如,描述列就是Windows 2000新添的信息。这就提供
了一些额外的描述性文本来解释有关服务正在做着什么。查看关于各项服务部分详细属性的能力也是Windows
2000的新特性。例如,我将向下滚动到脱机打印服务并单击鼠标右键,进而在出现的快显菜单上选择属性项
目,接下来所显示出的属性之一就是可执行程序的路径。为什么说这一点很重要呢?原因就是,服务名并不
总是直接映射到包含构成服务功能代码的可执行文件名上,换言之,如果你正在查看任务管理器并发现有一
个服务进程正在运行着,则该项服务的可执行文件名也许并不能马上告诉你它到底是不是控制面板中所显示
的那项服务功能。让我们接着看下一张幻灯片,它显示了如何将你在系统中所看到的服务活动映射到在注册
表中所定义的服务活动的途径。好的,我们刚才看到了如何将一个服务映射到可执行文件名的过程,但我们
应如何执行这个过程的逆过程呢?Tlist通过添加一个我们尚未使用过的参数——/s来解决这个问题。该参数
所显示的内容是为那些包含服务的进程而设计的,正如我现在以白色加亮显示的运行于进程中的服务名那样
。请注意,某些服务进程包含着象脱机打印那样的单项服务,而另一些则包含多项服务,而这就意味着在已
知这些服务进程正在运行哪项服务的前提下,仍旧难以解释CPU时间的占用问题,但你毕竟已将该问题收缩
到一个更小的范围内了。请记住,在第三列中所显示的名字并不是你在控制面板中所看到的那些,因为,服
务实际上有三个名字:系统管理员在控制面板中所看到的名字、包含该服务的可执行文件的名字以及注册表
中的服务名。Tlist所显示的是注册中的服务名。因此,如果你进入注册表并查看服务列表(该列表存在于H
键本地机当前控制服务中),那就是你能够按字母顺序查看的注册表键名。在这个注册表键之下,便是你将
在控制面板中看到的显示名称以及可执行文件的名称。因此,有了TList/t这个工具,你将至少能在一定程度
上对这些服务进程中的某一个进程是否正处于运行状态做出判断,而恰恰是一个或多个服务导致了对CPU时间
的占用。
我们最后一节的内容涉及在进程崩溃时观察其反常的进程活动。没有人愿意看到应用程序崩溃的情况,但我
相信你们中的所有人至少都看到过屏幕上半部分显示的内容——著名的Dr. Watson程序产生的消息框。现在
,我们所看到的实际上是在Windows 2000中更新过的Dr. Watson消息框,它比NT 4.0中同样的消息框少了一
点信息。Windows NT 4.0在该消息框中显示应用程序崩溃的原因。并且将其标注为Dr. Watson。现在它仅被
标注为应用程序错误并且添加了一些NT 4.0中没有的帮助性文字,主要包括“你需要重新启动程序”这句话
。虽然大多数用户都知道应当这样做,但这个消息框还是更清楚的指明了应用程序的崩溃。你需要重新启动
程序。不幸的是,它依旧没有告诉用户对于应用程序的崩溃可以做些什么。它仅显示了一条产生出来的出错
日志记录。那
么,这个出错日志记录在哪里以及针对其做了些什么呢?这正是我们将在这一节中考虑的问题。首先,如何
导致一个进程崩溃呢?产生一个不可处理的异常,例如引用一个非法的内存地址、或被0除。大多数Windows
NT 4.0和Windows 2000系统被配置为在应用程序出错时运行Dr. Watson。注册表中的AE Debug键指示了调试
器的名称,该键位于软件分支中。如果找到该注册表键,你会发现在大多数情况下它被配置为调试器Dr. Wa
tson,Dr. Watson并非一个真正的调试器,而只是一个在进程崩溃时产生信息快照的事后工具。如果你已经
安装了Visual Studio或一些其它的开发工具,注册表可能已经被修改,不再使用Dr. Watson,取而代之,以
Visual Studio开发环境为例,当进程崩溃时,你将会看到屏幕下方显示的针对程序员的消息框,其中包括了
有关异常的详细信息并且给程序员一个退出程序或运行调试器的选项。但在大多数情况下,还是会显示上面
的消息框。
一个程序崩溃时会发生什么呢?首先,让我们产生一个这样的情况并看一看它的结果。让我们回到命令行方
式并在演示目录中运行一个将立即导致访问违规的程序,该程序中引用了0地址这样一个非法地址。一个由D
r. Watson产生的消息框显示出来,并且同时创建了一条出错日志记录,我们还不知道它来自何处,因此,
单击确定。下面,我们将通过交互地运行Dr. Watson工具来确定出错日志记录的位置。我将运行DrWtsn32,
它是组成Dr. Watson工具的程序名称。当交互运行Dr. Watson工具时,它显示一个配置对话框以告诉你日志
文件和故障转储文件的位置,尽管在消息框中没有提到,但可以看出故障转储文件显然是被创建的。Window
s NT 4.0和Windows 2000中的缺省动作是为Dr. Watson创建一个日志文件和一个故障转储文件。其中命名为
user.dmp的故障转储文件包含死亡进程私有内存空间中的内容。日志文件中包含了不知是否对程序员有所帮
助的文本信息。User.dmp文件包含了进程的精确状态。换言之,它包含了进程死亡时沙箱中的脏沙子。转储
文件可被程序员应用于一个称为windbg的工具或Windows调试器中,以便观察进程崩溃时的状态,这将有希
望能够调试或诊断问题。现实中,对于每个崩溃的进程,都应向程序所有者发送一个user.dmp文件。例如,
如果Outlook崩溃了,并且是一个未知的问题,那么应向Microsoft发送一个转储文件。如果是一个第三方软
件,那么应向其厂商发送一个user.dmp文件。转储文件每次使用时都将被覆盖,与此相反,日志文件缺省时
是被追加的。日志文件将保存所有进程崩溃的跟踪信息,不幸的是,user.dmp文件每一次都将被覆盖。因此
,除非使用某些机制或保证用户
已被培训为能够定位和重命名文件,否则,只有最近的死亡进程信息将被保留。
当前所说的不是由系统崩溃产生的NT核心故障转储,而是一个进程崩溃产生的转储文件。不同的工具将用于
观察这两种转储文件。最基本的,如果你的用户遇到了一个Dr. Watson错误或程序错误,某个人应当获取转
储文件并尽快将其转移到他自己的系统中,改变其名称并将其送往厂商。另一个与系统崩溃有关的工具是作
为调试工具的一部分新添加到Windows 2000中的称为增强用户转储工具的程序。该工具将在从用户诊断CD中
安装调试工具时被安装。该工具可以完成而Dr.Watson目前尚不能实现的功能是,在不影响进程的情况下为一
个挂起的正在执行中的进程生成一个user.dmp文件。现在,如果有一个挂起的程序,并且你唯一的选择是杀
死这个进程。这种情况下,也有一种获得内存快照的方法,以使你能够将其发送给厂商并期望问题得以解决
。这种方法是配置成从命令行状态或通过预定义的快捷键(这在不能切换到命令行状态时非常有用)运行该
工具。为了获取更多信息,可以参考Windows 2000调试工具的帮助文件。
以上是有关理解Windows NT 4.0和Windows 2000系统及进程活动的内容。我希望通过我们已经看到的这些手
头的工具,在系统运行缓慢或不知何故出现故障时,你能够深入到进程或系统活动内部并查明CPU时间究竟
耗费在了什么地方以及为什么会这样。
想要获得更多信息,在TechNet网站上的文章中可以得到大量有关NT故障诊断的信息。当然,Windows 200
0的Microsoft官方课程也很有用。TechNet网站上的Windows 2000技术中心是另一个很好的参考资源。在幻
灯片的下部还有一些关于Window 2000操作系统的有用信息,例如,我的著作“Inside Windows 2000 第二
版”、Windows 2000资源工具包中包含的大量关于NT系统配置的宝贵信息、以及另外一个你可能并未想到要
去访问的网页——硬件开发者网页(microsoft.com/hwdev),该网页包含一些驱动程序编写者感兴趣的NT
内部文章。最后,在sysinternals.com网站上还有一些附加工具和技术信息。