如何使用远程工具跟踪 Windows CE 应用程序中的内存泄漏

来源:互联网 发布:java计算剩余天数 编辑:程序博客网 时间:2024/05/17 15:20

如何使用远程工具跟踪 Windows CE 应用程序中的内存泄漏

发布日期 : 4/6/2005 | 更新日期 : 4/6/2005

Mike Hall
Microsoft

适用于:
Microsoft Windows CE 5.01

摘要:本文提供了有关调试工具的实践性概述,该调试工具可用于跟踪基于 Windows CE 的应用程序或驱动程序中的泄漏。您将针对运行在 Windows CE 仿真程序上的 Windows CE 5.0 操作系统映像来创建、自定义、构建、下载、调试以及使用远程工具。
该实验大约需要 60 分钟完成。

从 Microsoft 下载中心下载 Windows CE 5.0 Embedded Development Labs.msi

本页内容

第 1 部分:创建平台映像 第 1 部分:创建平台映像
第 2 部分:自定义和构建平台 第 2 部分:自定义和构建平台
第 3 部分:下载平台 第 3 部分:下载平台
第 4 部分:远程工具和内存泄漏 第 4 部分:远程工具和内存泄漏
第 5 部分:其他 Windows CE 远程工具 第 5 部分:其他 Windows CE 远程工具
小结 小结

第 1 部分:创建平台映像

在 Platform Builder 内使用 New Platform Wizard 来创建初始平台工作区,之后通过添加应用程序以及更新注册表对其进行修改。

单击 Start | All Programs | Windows CE 5.0 | Platform Builder 启动 Platform Builder。现在,就可以通过使用 Platform Wizard 来创建平台了。

可以单击该缩略图以查看大图像。

要创建新平台工作区

  1. 选择 File | New Platform

    下图中的对话框概述了创建平台的过程。现在,需要按照向导的提示逐步执行,并进行相应的选择。

    单击 Next

    如下图所示,New Platform Wizard 的下一步将提示您输入要构建的平台名称和位置。在 Microsoft Windows CE 4.2 中,将在 C:/WINCE420/PUBLIC 文件夹中创建自定义平台。Windows CE 5.0 会将自定义工作区分隔在一个名为 C:/WINCE500/PBWorkspaces新文件夹中。

  2. 输入名称 MyPlatform

  3. 单击 Next

    通过选择 EMULATOR:X86 为 Windows CE 5.0 仿真程序构建一个操作系统,如下图所示。如果需要,可以选择多个参考板。然后,在构建时,可以选择构建和下载哪个平台。在硬件仍处于开发阶段时,选择仿真程序和参考板会比较有用,因为这样您可以在仿真程序中配置和测试操作系统映像,而无需物理硬件。

    WindowsCE_Advanced03thumb

  4. 单击 Next

    现在,可以从许多示例平台中进行选择,或者,如果没有一个选项符合您的需要,则可以只选择 Custom Device 并根据从目录选取的组件来构建映像。

    由于本教程的目的所在,您需要从平台配置列表中选择 Internet Appliance,如下图所示。

  5. 单击 Next

    每个示例平台都有许多选项可供选择,而 Platform Wizard 只显示与您要构建的平台相关的选项。例如,在 headless 设备(例如,网关)中包括 Internet Explorer 或 WordPad 应用程序毫无意义。Internet 应用设备可以包括诸如 Internet 浏览器、Microsoft Windows Media Player 和 Microsoft Windows Messenger 之类的应用程序,也可以选择性地包含其他应用程序。可以通过包含来自目录的组件或从项目工作区中移除组件,以进一步对平台进行自定义。

    在本例中,如下图所示,无需 Microsoft .NET Compact Framework 或任何 Windows Media 组件,因此可以将这些项清除。

  6. 单击 Next

    在 Networking and Communications 页上,您可以看到 Windows CE 对个人网络、局域网及广域网均支持。如下图所示,在本例中,采用默认选项即可。

  7. 单击 Next

    如下图所示,即可完成向导。您已经配置了 Windows CE 平台,现在,通过向平台添加或从其中移除组件,可以对平台进行进一步的自定义。

  8. 单击 Finish

现在,您就具有了包含所有选自 Platform Wizard 的 Windows CE 组件的平台工作区。通过向工作区添加其他技术和特定于平台的驱动程序,可以进一步自定义该平台,或者,可以移除任何由向导添加但您的平台并不需要的组件。

返回页首

第 2 部分:自定义和构建平台

在本部分练习中,您将执行以下过程:

  • 启用分析内核和事件跟踪

  • 创建 memLeak 应用程序,并将其添加到平台

  • 创建 GDILeak 应用程序,并将其添加到平台

  • 创建 Philosophers 应用程序,并将其添加到平台

  • 配置 Philosophers 应用程序

  • 构建平台

默认构建选项是生成操作系统的 Release 映像。如下图所示,使用工具栏从 Release 构建切换到 Debug 构建。

现在就可开始构建平台了。但是,在第 4 部分:远程工具和内存泄漏中,将使用 Remote Kernel Tracker 工具,因此,需要启用分析内核。

要启用分析内核和事件跟踪

  1. 选择 Platform | Settings

  2. Platform Settings 对话框上选择 Build Options 选项卡,如下图所示。

    您会注意到之前的图示中,工具当前设置为构建平台的 Debug 映像。虽然启用了内核调试,但是要使用 Remote Kernel Tracker 工具,还需要启用分析内核和事件跟踪。

  3. 选择 Enable Profiling

  4. 选择 Enable Event Tracking During Boot

  5. 单击 OK

您已向自己的平台添加了三个应用程序:memLeak、GDILeak 和 Philosophers。这些应用程序的源代码已经被写入并存储在 Code Clip 应用程序中。现在,需要创建这些应用程序并将其添加到平台工作区。

memLeak 应用程序是带有用户界面的 Windows 应用程序。您可以使用该应用程序来呈现调试区域以显示来自应用程序或驱动程序的重要调试信息、如何使用 Remote Performance Monitor 来监视操作系统内的内存负载,以及如何使用 CeLogData 将自定义数据项输出到 Remote Kernel Tracker 数据流中。memLeak 应用程序是多线程的,使用项目向导来创建该应用程序。本实验稍后部分,将对该应用程序中使用的代码进行分析。

要创建 memLeak 应用程序并将其添加到平台

  1. 选择 File | New Project or File

  2. 选择 WCE Application,如下图所示。

  3. Project name 框中,键入 MemLeak

  4. 单击 OK

  5. 键入您的特征信息,如下图所示,然后单击 Next

    如下图所示,出现三个选项:An empty projectA simple Windows CE applicationa typical "Hello World" application

  6. 选择 A simple Windows CE application

  7. 单击 Finish

项目向导已经创建了一个简单的 Win32 应用程序,该应用程序带有 WinMain 的入口点,无其他代码。现在需要向该应用程序添加一些代码。

  1. Workspace 窗口中,选择 File View

  2. 将工作区展开至 Projects | MemLeak | Source files

  3. 双击 MemLeak.cpp。该步骤将打开 memLeak 应用程序的源代码。

  4. 选择该应用程序的所有代码。

  5. DELETE 以删除所有代码。

  6. 从桌面打开 Code Clip。.

  7. 找到并打开 Platform Builder Advanced Lab 项。

  8. 双击 MemLeak。该步骤会将 memLeak 源代码复制到剪贴板。

  9. 在 Platform Builder 中,选择 Edit | Paste,或右键单击 Paste。memLeak 代码被添加至代码窗口。

现在,可开始向平台添加第二个应用程序了:GDILeak。该应用程序是一个带有用户界面的 Windows 应用程序。GDILeak 应用程序将用于说明如何使用 Application Verifier 工具来检查应用程序的运行库。在编写 Win32 应用程序时,可能容易忽略一个图形设备接口 (GDI) 句柄,创建该句柄是用于绘制应用程序的工作区的。每个未释放回操作系统的 GDI 句柄都泄漏 4 个字节。这个数量会随着时间的推移而增长,因此,需要运行 Application Verifier 工具来检查该应用程序的运行库。

要创建 GDILeak 应用程序并将其添加到平台

  1. 选择 File | New Project or File

  2. 选择 WCE Application,如下图所示。

  3. Project name 框中,键入 GDILeak

  4. 单击 OK

  5. 键入您的特征信息,如下图所示,然后单击 Next

    如下图所示,出现三个选项:An empty projectA simple Windows CE applicationa typical "Hello World" application

  6. 选择 A simple Windows CE application

  7. 单击 Finish

项目向导已经创建了一个简单的 Win32 应用程序,该应用程序带有 WinMain 的入口点,无其他代码。现在,需要向该应用程序添加一些代码。

  1. Workspace 窗口中,选择 File View

  2. 将工作区展开至 C:/WINCE500 | Projects | GDILeak | Source files

  3. 双击 GDILeak.cpp。该步骤将打开 GDILeak 应用程序的源代码。

  4. 选择该应用程序的所有代码。

  5. 按 DELETE 以删除所有代码。

  6. 从桌面打开 Code Clip

  7. 找到并打开 Platform Builder Advanced Lab 项。

  8. 双击 GDILeak。该步骤会将 GDILeak 源代码复制到剪贴板。

  9. 在 Platform Builder 中,选择 Edit | Paste,或右键单击 Paste。GDILeak代码被添加至代码窗口。

现在,可开始向平台添加最后一个应用程序了:Philosophers。该应用程序是一个带有用户界面的 Windows 应用程序。在本例中,将使用“进餐的哲学家”问题,一个经典的多进程同步问题。该问题中,五位哲学家围桌而坐,他们只做两件事:思考和进餐。每位哲学家之间,有一支筷子。为了进餐,每位必须具备两支筷子。如果每个人都先取右侧的筷子,然后再拿左侧的筷子,会出现一个问题。在这种情况中,出现了僵局,所有的哲学家都会挨饿。而且,这些哲学家应当机会平等并且不会长时间占有筷子;因此,每位哲学家的进食量应当彼此相等。

要创建 Philosophers 应用程序并将其添加到平台

  1. 选择 File | New Project or File

  2. 选择 WCE Application,如下图所示。

  3. Project name 框中,键入 Philo

  4. 单击 OK

  5. 键入您的特征信息,如下图所示,然后单击 Next

    如下图所示,出现三个选项:An empty projectA simple Windows CE applicationa typical "Hello World" application

  6. 选择 A simple Windows CE application

  7. 单击 Finish

项目向导已经创建了一个简单的 Win32 应用程序,该应用程序带有 WinMain 的入口点,无其他代码。现在,需要向该应用程序添加一些代码。

  1. Workspace 窗口中,选择 File View

  2. 将工作区展开至 C:/WINCE500 | Projects | Philo | Source files

  3. 双击 Philo.cpp。该步骤将打开 Philo 应用程序的源代码。

  4. 选择该应用程序的所有代码。

  5. 按 DELETE 以删除所有代码。

  6. 从桌面打开 Code Clip

  7. 找到并打开 Platform Builder Advanced Lab 项。

  8. 双击 Philosophers。该步骤会将 Philosophers 源代码复制到剪贴板。

  9. 在 Platform Builder 中,选择 Edit | Paste,或右键单击 Paste。Philosophers Ô´代码被添加至代码窗口。

现在,要针对 Philosophers 应用程序来运行 Remote Call Profiler。为此,需要确保 Philo 项目配置正确。

要配置 Philosophers 应用程序

  1. File 视图中,右键单击 Philo Project(Philo 应用程序的顶部节点)。

  2. 选择 Settings

  3. 选择并打开 Custom Variables,如下图所示。

  4. 单击 New,如下图所示。

  5. Variable name 框中,键入 WINCECALLCAP,如下图所示。

  6. Variable value 框中,键入 1

  7. 单击 OK

您还需要为该项目生成 .map 文件。

  1. Custom Variables 对话框中,单击 New

  2. Variable name 框中,键入 WINCEMAP,如下图所示。

  3. Variable value 框中,键入 1

  4. 单击 OK

  5. 单击 OK

现在,就可以开始构建平台了。

要构建平台

  • 选择 OS Design View

  • 选择 Build OS | Sysgen

构建过程需要大约 10 分钟来完成。

返回页首

第 3 部分:下载平台

在本部分练习中,您将执行以下过程:

  • 配置调试和内核传输

  • 下载操作系统

在下载操作系统映像之前,请检查以确保配置了调试和内核传输。

要配置调试和内核传输

  1. 选择 Target | Connectivity OptionsTarget Device Connectivity Options 对话框打开,如下图所示。

  2. DownloadTransport 框中,选择 Emulator

  3. 单击 Download 框旁边的 Settings。Emulator Download Settings 对话框打开,如下图所示。

    您可以在该对话框中为 Windows CE 仿真程序设置下载选项。该仿真程序作为功能完整的 x86 CEPC 参考板运行,并通过使用开发计算机的硬件设备包括对网络设备、串行设备以及并行设备的支持。

  4. 在 Memory 框中,选择 64

  5. 单击 OK

  6. 单击 OK 关闭 Target Device Connectivity Options 对话框。

现在,就可以开始下载操作系统了。

要下载操作系统

  • 选择 Target | Attach Device

将操作系统映像下载到该仿真程序。操作系统下载完成后,您会看到许多显示在 Platform Builder 中的调试消息。

返回页首

第 4 部分:远程工具和内存泄漏

在本部分练习中,您将执行以下过程:

  • 使用 Remote Performance Monitor 工具来监视当前内存负载。

  • 运行 memLeak 应用程序以在 Remote Performance Monitor 上显示泄漏

  • 在 memLeak 应用程序中查看调试区域信息

  • 使用 Remote Kernel Tracker 工具来查看当前内存负载

  • 停止 memLeak 应用程序

Remote Performance Monitor 是一个图形工具,该工具用于估量 Windows CE 远程系统的性能。您可以查看诸如处理器、内存、线程以及进程等性能对象的行为。每个性能对象都具备一套相关性能计数器,用于提供有关用于设备使用率、队列长度以及延迟的信息,和用于测量吞吐量及内部拥塞的信息。Remote Performance Monitor 能够跟踪目标设备上的当前活动,以及从日志文件查看数据。

您将使用 Remote Performance Monitor 来监视参考板上的内存负载。该工具对于一段时间内的内存负载跟踪很有用;如果内存负载随时间增加,则该增加可能是当前运行着的进程和驱动程序的正常行为,或者,它可能表示内存泄漏。您将使用 memLeak 应用程序以说明如何使用 Remote Performance Monitor。

要使用 Remote Performance Monitor 工具来监视当前内存负载

  1. 在 Platform Builder 中,选择 Tools | Remote Performance Monitor。系统会提示您要连接至的设备。

  2. 展开 Windows CE Default Platform,然后选择 Default Device

  3. 单击 OK。在连接到设备后,需要选择希望监视的性能项。在本过程中,需要监视内存负载。

  4. 选择 Edit | Add to Chart。Add to Chart 对话框中显示的默认对象是电源和电池状态,如下图所示。

  5. Object 框中,选择 CE Memory Statistics,如下图所示。

  6. 在 Counter 框中,选择 Memory Load

  7. 单击 Add

    单击 Done。现在,Remote Performance Monitor 将显示当前内存负载,它应当是一条没有起伏的直线。您可以从下图看出,操作系统正以大约百分之十七的内存负载在运行。

现在,运行泄漏内存的 memLeak 应用程序,并将泄漏显示在 Remote Performance Monitor 上。

要运行 memLeak 应用程序以将泄漏显示在 Remote Performance Monitor

  1. 在 Platform Builder 中,选择 Target | Run Program。Run Program 对话框将显示出 MyPlatform 工作区构建目录中的所有可执行程序,如下图所示。

  2. Available Programs 列表中选择 MemLeak.exe

  3. 单击 Run

    在 Remote Performance Monitor 中,您会注意到图形清楚地显示了系统中内存负载的变化,如下图所示。您也可以通过使用 GlobalMemoryStatus 应用程序编程接口 (API),直接从应用程序获取内存负载信息。

    该性能监视器使用结束后,就可以关闭该工具了。

  4. 选择 File | Exit

现在,memLeak 应用程序已运行,您可以开始探究调试区域了。区域允许开发人员将冗长的调试消息输出动态地更改为内核调试程序。这种更改在试图缩小问题原因的范围时非常有用。

调试区域和 Windows CE Console Debug Shell 工具 (Cesh.exe) 能够通过使用宏,选择性地打开和关闭来自代码的调试消息输出。这允许您跟踪代码的执行状况,而无需暂停操作系统。跟踪是一种简单的非侵扰式的捕获代码中问题的方式,而不会导致操作系统停止响应。调试区域可以通过 Target Control 或 Platform Builder 集成开发环境 (IDE) 启用。

调试区域通过在源代码中声明 DBGPARAM 结构来实现。在 dbgapi.h 中定义 DBGPARAMDBGPARAM 包含三个元素。您可以通过 dbgapi.h 中的结构定义来查看这些元素。

typedef struct  DBGPARAM {  WCHAR    lpszName[32];     // @field Name of module  WCHAR   rglpszZones[16][32]; // @field names of zones for first 16 bits  ULONG   ulZoneMask;          // @field Current zone Mask} DBGPARAM, *LPDBGPARAM;

以下代码示例说明了如何在 memleak 应用程序中定义 DBGPARAM 结构。在本例中,只需要定义三个区域:初始化、函数跟踪以及内存分配/释放。您还可以看到,初始化是作为默认区域启用的。可以为任何或所有其他区域添加跟踪。

DBGPARAM dpCurSettings = {    TEXT("MemLeak"), {        TEXT("Init"),TEXT("Trace Fn( );"),TEXT("Memory"),TEXT(""),        TEXT(""),TEXT(""),TEXT(""),TEXT(""),        TEXT(""),TEXT(""),TEXT(""),TEXT(""),        TEXT(""),TEXT(""),TEXT(""),TEXT("")},    // By default, turn on the zones for init and errors.    ZONEMASK INIT    }; 

memLeak 应用程序与多数操作系统一样,构建时包含了调试区域信息。

要查看 memLeak 应用程序中的调试区域信息

  1. 在 Platform Builder 中,选择 Target,然后选择 CE Debug Zones。Debug Zones 对话框出现,如下图所示。

  2. 单击 Name 列表中的 memLeak.exe,之后,您会注意到 Debug Zones 列表中的区域信息会进行动态更新。

    通过示范区域,您将启用 Trace Fn() 消息。该选择将在应用程序分配和释放内存时,启用调试输出消息。

  3. Debug Zones 列表中,选择 Trace Fn( );,如下图所示。

  4. 单击 OK

    以下是来自 memLeak 应用程序的输出。您可以看到应用程序流:AllocateMemoryUseMemory 以及 FreeMemory。您正在跟踪这些函数的入口点和出口点。

    --------------------------------------------4294949561 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Enter - AllocateMemory( ) Function4294949563 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Leave - AllocateMemory( ) Function4294949563 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Enter - UseMemory( ) Function4294949564 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Leave - UseMemory( ) Function4294949564 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Enter - FreeMemory( ) Function4294949564 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Leave - FreeMemory( ) Function4294950065 PID:2dda5912 TID:4dda5d36 0x8dd806dc: --------------------------------------------

    该输出只是显示了应用程序流,但是它没有提供有关内存分配的更多其他调试信息。您可以启用第二个调试区域以从应用程序获取更多信息。接下来,将启用内存跟踪。

  5. 在 Platform Builder 中,选择 Target,然后选择 CE Debug Zones。Debug Zones 对话框出现。

  6. 单击 Name 列表中的 memLeak.exe,您会注意到 Debug Zones 列表中的区域信息会进行动态更新。

  7. Debug Zones 列表中,选择 Memory

  8. 单击 OK

    以下是来自 memleak 应用程序的更新调试信息。突出显示的区域显示了通过启用内存跟踪而增加的其他调试信息。

    -------------------------------------------- 187306 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Enter - AllocateMemory( ) Function 187306 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Check GlobalMemoryStatus( ) 187306 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Memory Load 24% 187307 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Allocate TCHAR *2048 (4096 UNICODE Characters) 187310 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Pointer 0x310030 187310 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Leave - AllocateMemory( ) Function 187310 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Enter - UseMemory( ) Function 187310 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Do Something Interesting here. 187311 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Leave - UseMemory( ) Function 187312 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Enter - FreeMemory( ) Function 187312 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Free Pointer 0x0 187312 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Leave - FreeMemory( ) Function 187814 PID:2dda5912 TID:4dda5d36 0x8dd806dc: -------------------------------

    在之前的输出中,您会看到从 0x310030 的 LocalAlloc 函数返回了一个指针。您也可以看到,FreeMemory 函数调用 LocalFree 函数并传递一个为零的指针值。您可以假设没有使用相同的变量来分配和释放内存。

  9. 为平台工作区选择 ClassView

  10. 展开 memleak 应用程序。展开的 memleak 应用程序显示了包含在 memleak 应用程序中的各种函数和变量,如下图所示。需要特别关注的是 AllocateMemoryFreeMemory 函数。

  11. ClassView 选项卡上,双击 AllocateMemory 函数。

    在以下代码示例中,正在分配 2048*sizeof(TCHAR)。调用 LocalAlloc 的结果被存储在 g tcTemp 变量中。

    if (g MemStatus.dwMemoryLoad < 60) {DEBUGMSG (ZONE MEMORY, (TEXT("Allocate TCHAR *2048 (4096 UNICODE Characters)/n")));    g tcTemp=LocalAlloc(LPTR,(2048*sizeof(TCHAR)));    DEBUGMSG (ZONE MEMORY, (TEXT("Pointer 0x%lx/n"),g tcTemp));} else {

    现在,可以考察 FreeMemory 函数了。

  12. ClassView 选项卡上,双击 FreeMemory 函数。

    可以清楚地看到,您要使用一个名为 g tc Temp 的变量来释放内存。该变量在应用程序初始化期间被初始化为 NULL。该示例使用了多个变量名。在该示例中,不正确的变量被释放了。

    void FreeMemory( ){   DEBUGMSG (ZONE TRACE, (TEXT("Enter - FreeMemory( ) Function/n")));   DEBUGMSG (ZONE MEMORY, (TEXT("Free Pointer 0x%lx/n"),g tc Temp));   LocalFree(g tc Temp);   DEBUGMSG (ZONE TRACE, (TEXT("Leave - FreeMemory( ) Function/n")));}

通过使用 Remote Kernel Tracker 工具,您可以查看线程交互、内部依赖项以及系统状态信息。该工具可显示出系统中的所有进程和线程;何时创建、运行或停止进程和线程;何时进程和线程休眠;系统中断以及系统事件。将这些系统事件映射到在其出现时执行的线程上。

Remote Kernel Tracker 工具是跟踪实时事件的重要工具(在阅读实时文章时可了解到该工具的工作原理)。但是,如何使用 Remote Kernel Tracker 工具来跟踪内存呢?答案很简单,通过使用对 CeLogData API 的调用来进行。

在以下 memleak 应用程序的代码中,通过调用 GlobalMemoryStatus 会获得当前内存负载。然后,通过将该内存负载用作参数之一来调用 CeLogData。在本例中,无论何时分配内存,都要输出内存负载。您可以输出任何有用的信息,包括句柄、事件、线程、内存分配以及可用内存。

MEMORYSTATUS g MemStatus;memset(&g MemStatus,0x00,sizeof(g MemStatus));g MemStatus.dwLength=sizeof(g MemStatus);GlobalMemoryStatus(&g MemStatus);DEBUGMSG (ZONE MEMORY, (TEXT("Memory Load %d%%/n"),g MemStatus.dwMemoryLoad));CeLogData(TRUE, CELID RAW LONG, &g MemStatus.dwMemoryLoad,  (WORD) (sizeof(DWORD)), 1, CELZONE MISC);

要使用 Remote Kernel Tracker 工具查看当前内存负载

  1. 在 Platform Builder 中,选择 Tools | Remote Kernel Tracker。系统会提示您要连接至的设备。

  2. 展开 Windows CE Default Platform,然后选择 Default Device

  3. 单击 OK

    Remote Kernel Tracker 工具将许多设备端组件下载到仿真程序。在下载完这些组件后,Remote Kernel Tracker 工具会显示出所有运行中的进程和中断。

  4. 在 Remote Kernel Tracker 工具,展开 Memleak.exe,如下图所示。

    您会注意到显示的两个线程:第一个线程(标识为 Memleak.exe)是应用程序线程,第二个线程(标识为 ?MemoryThread)每隔 500 毫秒检查一次内存负载。如果内存负载低于百分之六十,则 ?MemoryThread 会分配 2048*TCHAR。

    因此,如何找到我们的自定义 CeLogData 信息?Remote Kernel Tracker 工具可以显示大量的信息。

  5. 右键单击 MemoryThread,如下图所示。

  6. 选择 Find Next Event on Thread

    Remote Kernel Tracker 工具将“跳”至选定线程上的下一个事件。您会注意到下图中,有一个带有四个点的白色方块。这个图形是自定义(或 CeLogData)项。

  7. 在白色方块上移动指针以查看“数据提示”。会显示代码输出的信息。

    您会注意到,下图中显示的数据提示具有 [Event Info] Raw long, 14 - 该数据提示说明,在调用 CeLogData 时,内存负载为百分之十四。(该值根据系统可能会有所不同。)

  8. 关闭 Remote Kernel Tracker 工具。如果提示保存来自 Remote Kernel Tracker 工具的数据,请选择 No

  9. 关闭 Remote Performance Monitor 工具。如果提示保存数据,请选择 No

还需要停止 memLeak 应用程序,可利用两种方式来完成此操作:通过 Windows CE Target Control 窗口或直接通过 Platform Builder 用户界面。

要停止 memLeak 应用程序

  1. 在 Platform Builder 中,选择 Target | CE Processes

  2. 选择 Memleak,如下图所示。

  3. 单击红色的 Close Process 按钮。

  4. 单击 YES 关闭此进程。

返回页首

第 5 部分:其他 Windows CE 远程工具

Windows CE 附带有许多可用于考察嵌入式设备所用操作系统的工具。您需要考察 Application Verifier 工具、Remote Call Profiler 工具以及 Monte Carlo Profiler 工具的使用情况。

Application Verifier 工具

在本部分练习中,您要执行以下过程:

  • 启动 Application Verifier 工具

  • 从 Application Verifier 工具考察 GDILeak.exe 应用程序的输出

Application Verifier 工具评估应用程序的稳定性,并检测常见的编程错误。该工具在应用程序运行的同时,附加至该应用程序并执行测试。有了此工具,您也许就能诊断出应用程序中的细小问题;反之,将很难在 Microsoft Windows CE 中诊断出它们。

Application Verifier 工具所运行的每个测试都称为填充程序。该工具将这一填充程序插入调用函数和预期目标函数之间的代码路径中。

对于给定的应用程序,您可以选择 Application Verifier 工具使用的填充程序来测试该应用程序。适用于该工具的填充程序示例包括内存泄漏测试、特定 API 使用测试以及内存损坏测试。

在本例中,将运行一个简单的 Win32 应用程序,该程序将位图显示在应用程序窗口的工作区中。要启用该功能,需通过使用 LoadBitmap 从应用程序资源加载位图,使用 GetObject 获得该位图的尺寸,将该位图选入临时设备上下文(通过使用 CreateCompatibleDC 创建的),然后,通过使用 BitBlt 将该位图复制到主设备上下文。

这个过程似乎非常简单,但是,Win32 开发人员仍然容易犯几个错误,例如,在没有清理结束使用资源的情况下,创建临时设备上下文。

以下是绘图例程的代码。

void DrawLogo(PAINTSTRUCT *ps){    HBITMAP hBmp=SHLoadDIBitmap(L"//Windows//Windowsce.bmp");    BITMAP bmp;    GetObject(hBmp,sizeof(bmp),&bmp);    HDC hDCTemp=CreateCompatibleDC(ps->hdc);    HBITMAP hBmpOld=(HBITMAP)SelectObject(hDCTemp,hBmp);    int iXPos=(ps->rcPaint.right-bmp.bmWidth)/2;    int iYPos=(ps->rcPaint.bottom-bmp.bmHeight)/2;    BitBlt(ps->hdc,iXPos,iYPos,bmp.bmWidth,bmp.bmHeight,hDCTemp,0,0,SRCCOPY);}

可以从 Windows CE Test Kit 启动 Application Verifier 工具。在以下过程中,您将启动 Application Verifier 工具并针对 ICOP x86 参考板运行它。

要启动 Application Verifier 工具

  1. 在 Platform Builder 中,选择 Tools | Application Verifier。Windows CE Application Verifier 对话框显示该工具未连接至目标设备,如下图所示。

  2. Application Verifier 工具使用一套填充程序 DLL 来截获 API 调用。Windows CE 附带有三个填充程序 DLL,这些填充程序 DLL 用于跟踪句柄 SHELL 和 HEAP。

    在示例应用程序 (GDILeak.exe) 中,先分配资源,然后,不要将这些资源交回操作系统。每个句柄泄漏 4 字节。这个量也许看来并不算非常大,但是,对于嵌入式系统生存期而言,随着应用程序在其上日复一日、月复一月甚至年复一年毫不间断地运行,这 4 字节泄漏可能会增加至数兆字节的内存。

  3. 单击 ConnectDevice Connection 对话框提示选择连接至目标设备的方式,如下图所示。

  4. 清除 Use Windows Sockets for the client/server communication 复选框。

  5. 在 Platform Manager 下,单击 Connect。系统会提示您要连接至的设备。

  6. 选择 Windows CE Default Device

  7. 单击 OK

现在,可以运行应用程序并从 Application Verifier 工具考察输出。需要从 Application Verifier 工具启动应用程序。在本例中,将跟踪用户和 GDI 对象。

要从 Application Verifier 工具考察 GDILeak.exe 应用程序的输出

  • 在 Application Verifier 工具中,选择 Shell Verifier,如下图所示。

  • 单击 Add 将测试设置添加至该测试。

  • 展开 Windows 文件夹,然后选择 GdiLeak.exe

  • 单击 Open

  • 单击 Run。下图显示了 x86 参考板上的应用程序外观。可以清楚地看到,从应用程序资源加载 Windows CE .NET 位图,并将其显示在应用程序的工作区上。

  • 关闭该应用程序。

    接下来,可以在 Application Verifier 工具中查看结果。

  • 在 Application Verifier 工具中,单击 Get Logs

  • 在 Application Verifier 工具中,单击 View Exported Log。在下图中,可以看到对 LoadBitmapCreateCompatibleDC 的调用中的泄漏。

应当在使用完对象后,调用 DeleteDCDeleteObject 来清理。

该过程举例示范了如何使用 Application Verifier 工具来跟踪应用程序中的泄漏。在本例中,使用了 GDI 对象。您还可以在该应用程序上运行其他测试,以验证句柄(文件、注册表)和堆的使用。

Remote Call Profiler 工具

在本部分练习中,将执行以下过程:

  • 通过 Remote Call Profiler 工具打开 Philosophers 应用程序

Remote Call Profiler 工具用图形接口将分析和解析工具合并,以使您能够识别代码中的算法瓶颈。

Remote Call Profiler 工具中的技术提供有图形环境,以显示希望分析的信息。您可以比较来自数据不同部分的信息,并以多种格式查看数据。

在本例中,将使用 Remote Call Profiler 工具来确定 Philosophers 应用程序中花费时间的地方。

要通过 Remote Call Profiler 工具打开 Philosophers 应用程序

  1. 在 Platform Builder 中,选择 Tools | Remote Call Profiler

  2. 连接到 Windows CE .NET Default Device

  3. 选择 Launch

  4. 在 Launch 对话框中,键入应用程序名 Philo.exe,如下图所示。

    Philosopher 应用程序将运行,但不显示任何用户界面。该应用程序的确将数据输出到 Platform Builder 中的调试窗口。以下是输出的示例。

    3722641 PID:e3c55f36 TID:23a08d72 #0 waiting forever on right chopstick 23a0889a3722643 PID:e3c55f36 TID:23a08d72 #0 waiting forever on left chopstick 23a088fa3722652 PID:e3c55f36 TID:239e2802 #1 Eating3722653 PID:e3c55f36 TID:239e2802 #1 waiting forever on right chopstick 23a088fa3722681 PID:e3c55f36 TID:239e2fa6 #2 Eating3722682 PID:e3c55f36 TID:239e2fa6 #2 waiting forever on right chopstick 23a0895a3722683 PID:e3c55f36 TID:239e2fa6 #2 waiting forever on left chopstick 23a08a623722691 PID:e3c55f36 TID:239e2f66 #3 Eating3722692 PID:e3c55f36 TID:239e2f66 #3 waiting forever on right chopstick 23a08a623722706 PID:e3c55f36 TID:239de1aa #4 Eating3722707 PID:e3c55f36 TID:239de1aa #4 waiting forever on right chopstick 23a08af23722708 PID:e3c55f36 TID:239de1aa #4 waiting forever on left chopstick 23a0889a3723145 PID:e3c55f36 TID:23a08d72 #0 PonderNothingness3723146 PID:e3c55f36 TID:239e2802 #1 waiting forever on left chopstick 23a0895a3723185 PID:e3c55f36 TID:239e2fa6 #2 PonderNothingness3723186 PID:e3c55f36 TID:239e2f66 #3 waiting forever on left chopstick 23a08af23723649 PID:e3c55f36 TID:239de1aa #4 PonderNothingness3723688 PID:e3c55f36 TID:239e2802 #1 PonderNothingness3724147 PID:e3c55f36 TID:23a08d72 #0 Eating3724148 PID:e3c55f36 TID:23a08d72 #0 waiting forever on right chopstick 23a0889a3724149 PID:e3c55f36 TID:23a08d72 #0 waiting forever on left chopstick 23a088fa3724151 PID:e3c55f36 TID:239e2f66 #3 PonderNothingness3724187 PID:e3c55f36 TID:239e2fa6 #2 Eating

    Remote Call Profiler 工具提供了许多数据视图。下图显示了 TopX 视图。该视图列出了所有在应用程序中调用的函数、每个函数的调用次数以及调用每个函数所花费的时间。您可以看到,大部分时间都花在了函数 MySleep 中。如果分析 MySleep 的代码,您会看到该函数调用 Sleep(dwMilliseconds)

    要使用 Remote Call Profiler 工具,应用程序必须包含 cecap.h,必须通过 /Gh 标志进行编译(或如果不是为 x86 构建,则为 /callcap),必须通过 cecap.lib 链接。x86 lib 文件在此处 — C:/Program Files/Common Files/Microsoft Shared/Windows CE Tools/Platman/sdk/wce420/platman/lib/target/x86。

Monte Carlo Profiler 工具

Monte Carlo Profiler 工具是一种统计软件诊断工具,其中操作系统频繁中断,并记录下这些中断地址。从该信息中,可导出每个例程的调用次数。这种类型的分析不会测量或记录执行时间。

Monte Carlo 分析提供了两种方法。第一种,称为进程分析,定期跟踪当前的运行例程。严格意义上讲,这是 Monte Carlo 分析。第二种分析技术,称为对象调用分析,类似于 Monte Carlo 分析。

Monte Carlo 分析依赖于支持 Windows CE 配置文件的内核(本文第 2 部分中,已启用了 Profiling 内核)。这一版本的内核包含进程和函数标识例程,以及结果收集和显示例程。进程分析方法还依赖于 OEM 适配层 (OAL) 的定期中断。

该分析器一启动就开始收集数据。停止后,它会分析数据并通过调试端口发送结果。

Windows CE 不会自动启动或停止该分析器。可以通过让应用程序调用 ProfileStartProfileStop 函数,来启动和停止该分析器。也可以利用默认键盘驱动程序(它支持控制该分析器的键)来启动和停止该分析器。此外,还可以使用 Target Control 窗口中的 prof 命令来控制该分析器。

要从 Windows CE Target Control 窗口使用 Monte Carlo Profiler 工具,请使用以下命令:

  • prof on — 打开分析

  • s philo — 启动 Philo.exe 应用程序(与使用 Remote Call Profiler 工具时所用应用程序相同)

  • prof off — 关闭分析

在关闭 Monte Carlo Profiler 工具之前,应当等待应用程序结束。

以下取自针对 Philo.exe 应用程序运行分析器后的输出。

Total samples recorded = 120814Module        Hits        Percent------------  ----------  -------nk.exe            118695     98.2coredll.dll          905      0.7tcpstk.dll           226      0.1afd.dll               52      0.0ndis.dll              46      0.0cxport.dll            26      0.0relfsd.dll            20      0.0Philo.exe             18      0.0gwes.exe              15      0.0VMini.dll             11      0.0netbios.dll            7      0.0filesys.exe            6      0.0fsdmgr.dll             4      0.0ddi.dll                4      0.0explorer.exe           3      0.0shell.exe              2      0.0pm.dll                 1      0.0commctrl.dll           1      0.0tapi.dll               1      0.0redir.dll              1      0.0ohci2.dll              1      0.0UNKNOWN              769      0.6Hits       Percent Address  Module       Routine---------- ------- -------- ------------:---------------------113891    94.2 8055ab26 nk.exe      : IDLE STATE   320     0.2 8054e977 nk.exe      : WaitOneMore   292     0.2 80549ca6 nk.exe      : KCNextThread   244     0.2 8054f292 nk.exe      : SC WaitForMultiple   153     0.1 805451e6 nk.exe      : RunqDequeue   144     0.1 8054b2d4 nk.exe      : SleepOneMore   134     0.1 80540c88 nk.exe      : memcpy   133     0.1 805430a4 nk.exe      : KCall   120     0.0 03fd10a0 coredll.dll : memset   103     0.0 8054921b nk.exe      : NextThread   101     0.0 8054191f nk.exe      : INTERRUPTS ENABLE   101     0.0 805430cd nk.exe      : Int22KCallHandler    98     0.0 80540c10 nk.exe      : memset     3     0.0 03f33e1b relfsd.dll  : write header     3     0.0 03f343aa relfsd.dll  : rreadnocs     3     0.0 03de1090 fsdmgr.dll  :?ExitVolume     3     0.0 03cc3a37 cxport.dll  : CTEpEventThread     3     0.0 03bc26d6 afd.dll     : WsaBufToNdisBuf     3     0.0 03bc5988 afd.dll     : EnterCriticalSection     3     0.0 03a5cf70 tcpstk.dll  : InterlockedIncrement     3     0.0 03a7990b tcpstk.dll  : UDPRcv     3     0.0 03a95e71 tcpstk.dll  : GetAddrType     3     0.0 00011915 Philo.exe   :?OutputDebug     3     0.0 00011ee3 Philo.exe   :?IsAvailable     3     0.0 0001257f Philo.exe   :?IsInhibitProfiling     2     0.0 00011018 Philo.exe   :?MyWaitForSingleObject     2     0.0 000120bf Philo.exe   :?CeCapInit     1     0.0 0001113a Philo.exe   :?MySleep     1     0.0 000114fa Philo.exe   :?Eat     1     0.0 000125c1 Philo.exe   :  penter     1     0.0 02cb8b2c ohci2.dll   :?GetPortStatus   773     0.6                      :

您可以从分析信息中看出,philo.exe 应用程序运行时,所需时间的 94% 花费在 IDLE STATE 中。

 

 

转自MSDN

原创粉丝点击