使用远程工具跟踪Windows CE应用程序中的内存泄漏(2)

使用远程工具跟踪Windows CE应用程序中的内存泄漏(2)

  原文地址http://frankjobs.bokee.com/2422131.html                                    

 

第 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 中定义 DBGPARAM。DBGPARAM 包含三个元素。您可以通过 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 应用程序的输出。您可以看到应用程序流:AllocateMemory、UseMemory 以及 FreeMemory。您正在跟踪这些函数的入口点和出口点。

--------------------------------------------
4294949561 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Enter - AllocateMemory( ) Function
4294949563 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Leave - AllocateMemory( ) Function
4294949563 PD:2dda5912 TID:4dda5d36 0x8dd806dc: Enter - UseMemory( ) Function
4294949564 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Leave - UseMemory( ) Function
4294949564 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Enter - FreeMemory( ) Function
4294949564 PID:2dda5912 TID:4dda5d36 0x8dd806dc: Leave - FreeMemory( ) Function
4294950065 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 应用程序中的各种函数和变量。需要特别关注的是 AllocateMemory 和 FreeMemory 函数。 
 
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 关闭此进程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值