.NET Compact Framework性能调试(环境篇/数据篇/分析篇)

来源:互联网 发布:知行网关于跳槽的论文 编辑:程序博客网 时间:2024/06/15 12:04

今天凌晨边做分析边写的博客,在CSDN这里把三篇合并一起吧。在国内似乎并没有研究Windows Mobile NetCF性能优化这块的文章,事实上.Net Compact Framework 1.0和2.0在内存管理上有很大的问题,如果没有分析的话一些复杂的NETCF程序会有严重的内存“泄露”问题。以下以文字为主,图片可以参考附加的老外的链接。没有碰到问题的人可以不用看了,因为很枯燥,碰到类似问题的人可以跟随着做一遍,会发现很多疑惑豁然开朗。

————————————————

环境篇:
———————————————

在追信项目(HTTP://WWW.ZHUI.CN)的WM版本开发发现中NETCF3.5以下版本有严重的内存问题。需要对性能进行调试。在网上可以搜到一堆资料,但对于调试部分也就几篇核心的。在《Microsoft Mobile移动应用开发宝典》一书也有描述,以下简单列一下。

参考网址:
http://blogs.msdn.com/stevenpr/archive/2006/04/17/577636.aspx
http://blogs.msdn.com/davidklinems/archive/2005/12/09/502125.aspx
http://blogs.msdn.com/stevenpr/archive/2007/03/08/finding-managed-memory-leaks-using-the-net-cf-remote-performance-monitor.aspx

1、在C:/Program Files/Microsoft.NET/SDK/CompactFramework/v2.0/WindowsCE/wce500/armv4i(或wce400)里可以找到netcflaunch.exe和netcfrtl.dll,拷贝到MOBILE设备(或虚拟设备)的WINDOWS目录下。
2、在C:/Program Files/Microsoft.NET/SDK/CompactFramework/v2.0/bin中可以找到NetCFRPM.exe,运行后选择"Live Counters...." 。
3、如果其中DEVICE为空,则运行刚才拷贝过去的netcflauch.exe,可以看到IP地址和端口。通常是127.0.0.1,端口为6510,然后在NetCFRPM的DEVICE里填看到的IP和端口,例如127.0.0.1 6510,用空格分开。
4、如果DEVICE不为空,则直接选择。
5、在APPLICATION输入程序路径,例如我的追信DEBUG的文件在“/Program Files/zhuiclient/ZhuiClient.exe”,然后点左下角的CONNECT。我之前第一次使用不行,清空虚拟机重开之后搞定。
6、出现了实时的调试画面,可以开始对照《Microsoft Mobile移动应用开发宝典》一点一点研究其中的含义去了~

————————————————

数据篇:
———————————————

在RPM中有很多数值,例如LOADER项目中就有以下:

 

Total Program Run Time (ms), 503745, The elapsed time from CLR invocation.
App Domains Created, 1, The count of App Domains created in the process.
App Domains Unloaded, 0, The count of App Domains that have been unloaded from the process.
Assemblies Loaded, 11, The count of assemblies that have been loaded - across all App Domains.
Classes Loaded, 1110, The count of classes that have been loaded - across all App Domains.
Methods Loaded, 3584, The total count of methods loaded - across all App Domains.

 

以下部分根据《Microsoft Mobile移动应用开发宝典》和自己的理解做摘要

 

Loader(加载程序):
App Domains Created,一般是1个,是指多少个程序集被载入。如果过多就有问题了。

 

Generics(泛型的使用情况),一般对性能影响不大的说

 

Locks and Threads(锁和线程)
尤其要关注Threads in Thread Pool,如果大于25(线程池最大容量),程序就会很卡。Work Items Queued,指排队的工作项。结合之前的线程池中的线程可以得到排队的工作与待处理的线程比。要注意的是程序中的SYSTEM.THREADING.TIMER也会使用使用线程。而Contested Monitor.Enter Calls指显式使用System.Threading.Monitor.Enter或隐式使用lock关键字是造成局部代码阻塞从而造成的程序卡住。

 

GC(垃圾回收)
Managed Bytes In Use After GC,如果在GC回收后此数值还是过大,需要尝试用STRINGBUILDER来替代一般的字符串连接。如果Boxed Value Types过高,说明值类型过多,装箱拆箱操作代价高。例如普通的LIST控件在System.Collections下,这时一般建议用泛型。另外还有一些参数有待研究……

 

Memory(内存)
这个需要重点关注的说……现在追信开发的焦点也在这个上面,主要是要考虑HEAP堆的问题。对程序有影响的是JIT Heap(JIT编译后本地代码空间占用)和GC Heap(为托管对象分配的控件统计)。另外三个是程序的大小。

 

JIT
各种JIT计数器,如果(Pitched)相关计数器过大,表示JIT重新编译的代码越高。如果程序运行,且没有切换到后台,丢弃方法(Methods Pitched)数值应为零。

 

Exceptions(异常)
处理TRY CATCH的代码比较高,需要尽可能减少,除了一些不可控因素,比如网络连接异常。而有些地方明知道如果是NULL就会出错,还是自己用IF ELSE来控制比较好。也就是说不能依赖于TRY和CATCH进行错误的捕捉。

 

Interop(互操作)
指调用本地代码的次数。貌似我的程序因为涉及到了调用C++开发的图形DLL,所以这个参数比较高,需要进一步研究对性能的影响。

 

Networking(网络)
没啥说的,出和进的字节数统计

 

Windows.Forms(窗体相关)
一般建议要复用窗体中的对象,比如字体、画笔等。


终于了解了RPM里输出的大概内容,准备进一步研究程序的瓶颈所在了。更详细的参数说明可以参考:
http://blogs.msdn.com/davidklinems/archive/2005/12/09/502125.aspx

 

————————————————

分析篇:
———————————————
2点了,继续研究追信程序的问题所在,嘿嘿。追信ZHUI.CN的WINDOWS MOBILE程序内存不断增加的问题在于过于依赖GC回收,而有些地方可能存在没有显示清理变量及CONTROL。那么接下来就是分析哪些内存没有被回收。

在RPM的左下角有个“VIEW GC HEAP”的按钮,点一下等会儿会出现查看垃圾回收堆的窗口。

窗体内分三块:


左上是统计项,包括多少的活的对象在堆中,以及对象总KB大小。


左下是类型窗,按照DLL啊类啊进行统计有多少instance(实例),需要注意这里的数值时累计,需要自己做快照前后比对。最左边CHECKBOX部分用来让这部分出现在右方列表窗进行分析。记得点了选中之后要点一下刷新按钮右边才会变动。而这个窗口的内容需要关闭后再打开View GC Heap才会刷新。


右方是Objects and their Roots树形列表。红色部分表示根。例如某个类,可以展开,看到root开头的红色的部分就是调用这个类的实例。在右边找到要分析的部分,右键选择“Display Object References”,就可以只查看这一部分。

 

在此窗体中选择FILE-SAVE可以保存当前快照,然后关闭此窗口,打开快照,再打开此窗口,就可以再VIEW中选择COMPARE模式了,可以比对区别。多保存几次(每次保存后程序做点操作),就可以查看实例数的变化了。有变化的相会红字标出并排在前面(可惜不能排序)。

以追信程序为例,之前发现的问题是窗体打开关闭,选项卡切换(重新载入其中内容)都会造成内存的不断增加,那就要通过这种方法确认到底是哪部分只有增加没有减少,而这个就是问题的关键了。

 

在实际操作中,通过初步4次快照的比对(每次都新开一个窗体再关闭),发现System.Windows.Forms.MenuItem和System.Windows.Forms.Menu.MenuItemCollection每次窗口关和开都会增长9,System.EventHandler也都增加9,那说明新开窗体的菜单项有内存泄露问题,在关闭后再打开并没有注销掉。System.Windows.Forms.Timer也都会每次+2,System.Windows.Forms.Label和MainMenu、PANEL、BUTTON、WebBrowser每次都+1。综上,根据实际的程序,说明打开新的FORM并关闭后,并没有释放资源(用了第三方窗体特效控件)。这样,一个问题就定位好了,接下去就是编码,看如何能够彻底销毁窗体里的资源了。

 

通过以上的边查资料边实际操作,已经基本可以确定问题所在,接下去就是该如何解决了,也就是如何释放那些资源。研究到到这里3点多了,大概问题定位,可以安心地睡了^ ^b

文章参考:
http://blogs.msdn.com/stevenpr/archive/2007/03/08/finding-managed-memory-leaks-using-the-net-cf-remote-performance-monitor.aspx

 

————————————————

 

原创粉丝点击