LiXiong's Debugging paper

《Windows用户态程序高效排错》

2006年9月21日 #

招聘职位:赴微软软件测试开发工程师(产品: Windows 7)

     摘要: 目前我们在开发和测试Win7下面的活动目录管理工具,用WPF写的。测试方面的三大重要任务: 1. 因为我们的产品是跟在Win7里面的,所以编译,发布流程是跟着Windows的走。换句话说,每次测试新版本都需要重新装刚刚编译出来的Windows 7。其次,活动目录不是一个机器就可以了,要搭建多个服务器节点(DC)。所以如何高效自动地完成测试环境的搭建是很有挑战的 2. 完成WPF程序的自动化测试。简单地说,就是要通过代码去模拟用户的UI操作。比如点鼠标,输入数据,点确定按钮等等。大家排排脑袋想下这个事情的难度。比如给你一个WPF写的计算器,你知道怎么做么?如何写出高效,稳定和全面的UI自动化也是很有挑战的 3. 熟悉活动目录。熟悉活动目录的就知道这个东西有多复杂。当然不熟悉的也没关系,不能指望一个人什么都知道 我们招人的目的就是做好上面三点工作。技术方面的话,能搞定C#和Windows就可以了。搞定的意思是指能搞定技术细节,比如: ......  阅读全文

posted @ 2008-07-18 22:45 lixiong 阅读(660) | 评论 (2)编辑

《Windows 高效排错》 可以在CSDN读书频道预览了

《Windows 高效排错》 可以在CSDN读书频道预览了

地址在这里:
http://book.csdn.net/bookfiles/555/

读书频道的排版有些问题,看起来不是很舒服。如果想看PDF的,可以在这里下载

http://www.cnblogs.com/lixiong/archive/2006/08/16/475520.html

纸板书籍估计在11月中下旬面世 

现在在China-pub, dearbook等网上书店已经有介绍,地址分别

http://www.china-pub.com/computers/common/info.asp?id=37008
http://www.dearbook.com.cn/book/230727

您的看法非常重要。如果你看过这本书的PDF,了解本书的内容和潜在读者,请您在上面的链接中留下你的观点,便于其它不了解这本书的人选择。

Dudu, 书中有关于cnblogs性能优化的案例,Jeffery Zhao,补充链接中有WCF Assembly Loading的案例。非常希望听到你们两位的评价。

如果您通过这本书介绍的方法解决过实际的问题,非常希望您能够分享您的经验。您可以发邮件到eparg@msn.com。如果您的分享能够帮助其它读者,我非常希望能够送书给您作为答谢。

如果您对书中所述内容有疑惑,也欢迎您写信来讨论。我会尽快回复。如果我们之间的讨论对其他读者有帮助,我也会放到网上,同时送书给您作为答谢。

posted @ 2007-11-07 21:57 lixiong 阅读(2461) | 评论 (33)编辑

三个关键命令找出ASP.NET程序内存分片的原因

最近一位朋友的ASP.NET程序怀疑有内存泄露问题。几个简单的页面,起来运行几分钟后,虚拟内存就到600多MB。从性能监视上看,private bytes只有200多MB。

这样的问题从经验上来说,十有八九都是内存碎片了。ASP.NET程序发生内存碎片的原因比较多,我常见的有:


1. Web.config中的debug=true,导致batch compilation=false,使得每一个ASPX页面都生成一个临时assembly。当页面比较多的时候,大量的assembly导致内存泄露。
2. 程序中误用了XmlSerializer。频繁的XML序列化导致大量的动态assembly
3. 程序中有大量的blocking IO操作,而且IO buffer没有及时释放。比如程序中有大量的Web Service调用,但是对方web service返回比较慢,使得调用程序中用来接收web service结果的小块buffer大量堆积,导致内存泄露

下面是我拿到dump后的分析步骤。对于managed程序,找出问题的大致线索还是挺简单的。


(随便无耻地推销下,《Windows高效排错》书中对这样的问题有更多的讨论。包括更多的案例和命令解释。该书最初的PDF草稿在http://www.cnblogs.com/lixiong/archive/2006/08/16/475520.html。如果有朋友从这个PDF中找到过排错的灵感,麻烦也帮忙无耻推销下。)


首先是看看CLR的版本了。这个直接看mscorwks文件或者mscorsrv文件。如果文件版本比较低,后面的就没必要仔细看了,升级CLR补丁后再说。


0:000> lmvm mscorwks
start    end        module name
79e70000 7a3d6000   mscorwks   (deferred)            
    Image path: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
    Image name: mscorwks.dll
    Timestamp:        Fri Apr 13 15:15:54 2007 (461F2E2A)
    CheckSum:         00564CA8
    ImageSize:        00566000
    File version:     2.0.50727.832
    Product version:  2.0.50727.832
    File flags:       0 (Mask 3F)
    File OS:          4 Unknown Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0409.04b0
    CompanyName:      Microsoft Corporation
    ProductName:      Microsoft® .NET Framework
    InternalName:     mscorwks.dll
    OriginalFilename: mscorwks.dll
    ProductVersion:   2.0.50727.832
    FileVersion:      2.0.50727.832 (QFE.050727-8300)

    FileDescription:  Microsoft .NET Runtime Common Language Runtime - WorkStation
    LegalCopyright:   © Microsoft Corporation.  All rights reserved.
    Comments:         Flavor=Retail

恩,版本还是比较新的。既然是内存问题,先看GC中有多少object,占用了多少内存

0:000> !eeheap -gc
Number of GC Heaps: 4
------------------------------
Heap 0 (000f3f10)
generation 0 starts at 0x02fad2fc
generation 1 starts at 0x02f83ff8
generation 2 starts at 0x02f00038
ephemeral segment allocation context: none
 segment    begin allocated     size
00109198 7a72c42c  7a74d308 0x00020edc(134876)
000fdfb0 790d5588  790f4b38 0x0001f5b0(128432)
02f00000 02f00038  03081450 0x00181418(1578008)
Large object heap starts at 0x12f00038
 segment    begin allocated     size
12f00000 12f00038  131b00a0 0x002b0068(2818152)
Heap Size  0x47190c(4659468)
------------------------------
Heap 1 (000f50a0)
generation 0 starts at 0x06f5b110
generation 1 starts at 0x06f5acf8
generation 2 starts at 0x06f00038
ephemeral segment allocation context: none
 segment    begin allocated     size
06f00000 06f00038  06ff511c 0x000f50e4(1003748)
Large object heap starts at 0x14f00038
 segment    begin allocated     size
14f00000 14f00038  14f00048 0x00000010(16)
Heap Size   0xf50f4(1003764)
------------------------------
Heap 2 (000f68a0)
generation 0 starts at 0x0af78634
generation 1 starts at 0x0af09d40
generation 2 starts at 0x0af00038
ephemeral segment allocation context: none
 segment    begin allocated     size
0af00000 0af00038  0af92a0c 0x000929d4(600532)
Large object heap starts at 0x16f00038
 segment    begin allocated     size
16f00000 16f00038  16f00048 0x00000010(16)
Heap Size   0x929e4(600548)
------------------------------
Heap 3 (000f7bc8)
generation 0 starts at 0x0ef7b270
generation 1 starts at 0x0ef7b264
generation 2 starts at 0x0ef00038
ephemeral segment allocation context: none
 segment    begin allocated     size
0ef00000 0ef00038  0ef7d27c 0x0007d244(512580)
Large object heap starts at 0x18f00038
 segment    begin allocated     size
18f00000 18f00038  18f00048 0x00000010(16)
Heap Size   0x7d254(512596)
------------------------------
GC Heap Size  0x676638(6776376)

内存占用只有6M,显然不是CLR object导致的问题。那看来真的就是内存碎片了。于是先看看程序中有多少DLL:
0:000> lmf
start    end        module name
00900000 00bc5000   xpsp2res C:\WINDOWS\system32\xpsp2res.dll
01000000 01005000   w3wp     c:\WINDOWS\system32\inetsrv\w3wp.exe
1b740000 1b748000   App_global_asax_incckcvw C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\b972f933\24c4c459\App_global.asax.incckcvw.dll
1b770000 1b790000   Boke_WebRoot_Admin C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\b972f933\24c4c459\assembly\dl3\0854db20\0aaa279d_a314c801\Boke.WebRoot.Admin.DLL
1b7e0000 1b820000   log4net  C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\b972f933\24c4c459\assembly\dl3\8af1019b\00a071ef_de00c801\log4net.DLL
1bb00000 1bb0e000   App_Web_fsrghzyk C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\b972f933\24c4c459\App_Web_fsrghzyk.dll
1bb20000 1bb30000   AspNetPager C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\b972f933\24c4c459\assembly\dl3\53ce5ce1\00a071ef_de00c801\AspNetPager.DLL
1bb30000 1bb3c000   App_Web_qenznn_e C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\b972f933\24c4c459\App_Web_qenznn_e.dll
1bb60000 1bb70000   UDMap    D:\webfolder\dvdvAdmin\bin\Map.dll
50210000 5025c000   SMDiagnostics_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\SMDiagnostics\da4366daf8361c62ed3fcec4c55fa9ca\SMDiagnostics.ni.dll
50270000 50368000   System_IdentityModel_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.IdentityModel\bc31a40dee949687576d5395efcab6a0\System.IdentityModel.ni.dll
504e0000 50728000   System_Runtime_Serialization_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Runtime.Seri#\c861896fa11d6eef9fed23cff7b77b01\System.Runtime.Serialization.ni.dll
507a0000 5185e000   System_ServiceModel_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.ServiceModel\719a7cce9b36b780b3edd9869ceb2537\System.ServiceModel.ni.dll
5a300000 5a307000   w3tp     c:\WINDOWS\system32\inetsrv\w3tp.dll
5a320000 5a332000   w3isapi  c:\WINDOWS\system32\inetsrv\w3isapi.dll
5a360000 5a36d000   w3dt     c:\WINDOWS\system32\inetsrv\w3dt.dll
5a390000 5a3e8000   w3core   c:\WINDOWS\system32\inetsrv\w3core.dll
5a3f0000 5a3f6000   w3comlog c:\WINDOWS\system32\inetsrv\w3comlog.dll
5a400000 5a408000   w3cache  c:\WINDOWS\system32\inetsrv\w3cache.dll
5a420000 5a431000   iismap   C:\WINDOWS\system32\iismap.dll
5b640000 5b658000   strmfilt C:\WINDOWS\system32\strmfilt.dll
5e620000 5e6da000   Microsoft_JScript C:\WINDOWS\assembly\GAC_MSIL\Microsoft.JScript\8.0.0.0__b03f5f7f11d50a3a\Microsoft.JScript.dll
5f270000 5f2ca000   hnetcfg  C:\WINDOWS\system32\hnetcfg.dll
60060000 60066000   aspnet_filter C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll
60070000 60075000   aspnet_isapi \\?\c:\WINDOWS\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll
608f0000 60901000   admwprox C:\WINDOWS\system32\admwprox.dll
60ba0000 60bb1000   wamreg   c:\WINDOWS\system32\inetsrv\wamreg.dll
62da0000 62da7000   lonsint  c:\WINDOWS\system32\inetsrv\lonsint.dll
637a0000 63d02000   System_Xml_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Xml\e342cc4334d3ab13ce752de73164c01b\System.Xml.ni.dll
64700000 6472d000   iisutil  c:\WINDOWS\system32\inetsrv\iisutil.dll
647b0000 647d7000   iisrtl   C:\WINDOWS\system32\iisrtl.dll
64890000 6498a000   System_Configuration_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Configuration\edc1f15b90b2c6a4dc59b305f14bb98d\System.Configuration.ni.dll
64e70000 6513c000   System_Data C:\WINDOWS\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll
65140000 657a6000   System_Data_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Data\42481d9f835b4b6c150c50d2642781b9\System.Data.ni.dll
65f20000 66ac6000   System_Web_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Web\83c662f1a20af1b2deea3f9a040ccbd6\System.Web.ni.dll
67150000 67159000   httpapi  C:\WINDOWS\system32\httpapi.dll
68000000 68035000   rsaenh   C:\WINDOWS\system32\rsaenh.dll
685b0000 685ba000   gzip     C:\WINDOWS\system32\inetsrv\gzip.dll
695a0000 697da000   System_Web_Mobile_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Web.Mobile\e7d2fee1612b52a914d8d253d5e49a7c\System.Web.Mobile.ni.dll
69890000 698d0000   System_Web_RegularExpressions_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Web.RegularE#\1fa927a42b36176da2cdc193f0435950\System.Web.RegularExpressions.ni.dll
6a2a0000 6a307000   webengine \\?\c:\WINDOWS\microsoft.net\framework\v2.0.50727\webengine.dll
6d0f0000 6d110000   iisres   c:\WINDOWS\system32\inetsrv\iisres.dll
71640000 7180d000   acgenral C:\WINDOWS\AppPatch\acgenral.dll
71ae0000 71ae8000   wshtcpip C:\WINDOWS\system32\wshtcpip.dll
71af0000 71b12000   shimeng  C:\WINDOWS\system32\shimeng.dll
71b20000 71b61000   mswsock  C:\WINDOWS\system32\mswsock.dll
71b70000 71ba6000   uxtheme  C:\WINDOWS\system32\uxtheme.dll
71bb0000 71bb9000   wsock32  C:\WINDOWS\system32\wsock32.dll
71bd0000 71be1000   mpr      C:\WINDOWS\system32\mpr.dll
71bf0000 71bf8000   ws2help  C:\WINDOWS\system32\ws2help.dll
71c00000 71c17000   ws2_32   C:\WINDOWS\system32\ws2_32.dll
71c40000 71c97000   netapi32 C:\WINDOWS\system32\netapi32.dll
745e0000 7489e000   msi      C:\WINDOWS\system32\msi.dll
75490000 754f5000   usp10    C:\WINDOWS\system32\usp10.dll
75e60000 75e87000   apphelp  C:\WINDOWS\system32\apphelp.dll
76190000 761a2000   msasn1   C:\WINDOWS\system32\msasn1.dll
761b0000 76243000   crypt32  C:\WINDOWS\system32\crypt32.dll
76290000 762ad000   imm32    C:\WINDOWS\system32\imm32.dll
76920000 769e2000   userenv  C:\WINDOWS\system32\userenv.dll
76aa0000 76acd000   winmm    C:\WINDOWS\system32\winmm.dll
76b70000 76b7b000   psapi    C:\WINDOWS\system32\psapi.dll
76c90000 76cb7000   msv1_0   C:\WINDOWS\system32\msv1_0.dll
76cf0000 76d0a000   iphlpapi C:\WINDOWS\system32\iphlpapi.dll
76e30000 76e3c000   rtutils  C:\WINDOWS\system32\rtutils.dll
76e40000 76e52000   rasman   C:\WINDOWS\system32\rasman.dll
76e60000 76e8f000   tapi32   C:\WINDOWS\system32\tapi32.dll
76e90000 76ecf000   rasapi32 C:\WINDOWS\system32\rasapi32.dll
76ed0000 76efa000   dnsapi   C:\WINDOWS\system32\dnsapi.dll
76f10000 76f3e000   wldap32  C:\WINDOWS\system32\wldap32.dll
76f50000 76f63000   secur32  C:\WINDOWS\system32\secur32.dll
76f70000 76f77000   winrnr   C:\WINDOWS\system32\winrnr.dll
76f80000 76f85000   rasadhlp C:\WINDOWS\system32\rasadhlp.dll
77010000 770d6000   comres   C:\WINDOWS\system32\comres.dll
77380000 77411000   user32   C:\WINDOWS\system32\user32.dll
77420000 77523000   comctl32 C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.3790.3959_x-ww_D8713E55\comctl32.dll
77670000 777a9000   ole32    C:\WINDOWS\system32\ole32.dll
777b0000 77833000   clbcatq  C:\WINDOWS\system32\clbcatq.dll
77b70000 77b84000   msacm32  C:\WINDOWS\system32\msacm32.dll
77b90000 77b98000   version  C:\WINDOWS\system32\version.dll
77ba0000 77bfa000   msvcrt   C:\WINDOWS\system32\msvcrt.dll
77c00000 77c48000   gdi32    C:\WINDOWS\system32\gdi32.dll
77c50000 77cef000   rpcrt4   C:\WINDOWS\system32\rpcrt4.dll
77d00000 77d8b000   oleaut32 C:\WINDOWS\system32\oleaut32.dll
77da0000 77df2000   shlwapi  C:\WINDOWS\system32\shlwapi.dll
77e00000 77e21000   ntmarta  C:\WINDOWS\system32\ntmarta.dll
77e40000 77f42000   kernel32 C:\WINDOWS\system32\kernel32.dll
77f50000 77feb000   advapi32 C:\WINDOWS\system32\advapi32.dll
78130000 781cb000   msvcr80  C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.42_x-ww_0DE06ACD\msvcr80.dll
79000000 79045000   mscoree  C:\WINDOWS\system32\mscoree.dll
79060000 790b3000   mscorjit C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorjit.dll
790c0000 79b90000   mscorlib_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\56cbcbd518a77421a852a37b61624936\mscorlib.ni.dll
79e70000 7a3d6000   mscorwks C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
7a440000 7ac06000   System_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System\19aba12bb5350aa99107e93bafbb4f51\System.ni.dll
7ade0000 7af6c000   System_Drawing_ni C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Drawing\e3104e1713757f14b54b7835be2a0e26\System.Drawing.ni.dll
7c800000 7c8c0000   ntdll    C:\WINDOWS\system32\ntdll.dll
7c8d0000 7d0ce000   shell32  C:\WINDOWS\system32\shell32.dll
7e020000 7e02f000   samlib   C:\WINDOWS\system32\samlib.dll
7f000000 7f009000   lpk      C:\WINDOWS\system32\lpk.dll

非常普通。也就这点DLL,根本没有导致内存碎片的潜力呀!不死心,看看是不是有很多线程被block住了。要是有个几百个线程,嘿嘿
0:000> ~
.  0  Id: 694.540 Suspend: 1 Teb: 7ffdd000 Unfrozen
   1  Id: 694.12a0 Suspend: 1 Teb: 7ffdb000 Unfrozen
   2  Id: 694.1040 Suspend: 1 Teb: 7ffda000 Unfrozen
   3  Id: 694.11f0 Suspend: 1 Teb: 7ffd9000 Unfrozen
   4  Id: 694.13d0 Suspend: 1 Teb: 7ffd7000 Unfrozen
   5  Id: 694.1338 Suspend: 1 Teb: 7ffd6000 Unfrozen
   6  Id: 694.10e4 Suspend: 1 Teb: 7ffd5000 Unfrozen
   7  Id: 694.e4c Suspend: 1 Teb: 7ffd4000 Unfrozen
   8  Id: 694.10a8 Suspend: 1 Teb: 7ffd3000 Unfrozen
   9  Id: 694.1144 Suspend: 1 Teb: 7ff9f000 Unfrozen
  10  Id: 694.1340 Suspend: 1 Teb: 7ff9e000 Unfrozen
  11  Id: 694.1484 Suspend: 1 Teb: 7ff9d000 Unfrozen
  12  Id: 694.1170 Suspend: 1 Teb: 7ff9c000 Unfrozen
  13  Id: 694.11d8 Suspend: 1 Teb: 7ff9b000 Unfrozen
  14  Id: 694.1768 Suspend: 1 Teb: 7ff9a000 Unfrozen
  15  Id: 694.173c Suspend: 1 Teb: 7ff99000 Unfrozen
  16  Id: 694.a80 Suspend: 1 Teb: 7ff98000 Unfrozen
  17  Id: 694.500 Suspend: 1 Teb: 7ff97000 Unfrozen
  18  Id: 694.1194 Suspend: 1 Teb: 7ff96000 Unfrozen
  19  Id: 694.16c8 Suspend: 1 Teb: 7ff95000 Unfrozen
  20  Id: 694.162c Suspend: 1 Teb: 7ff94000 Unfrozen
  21  Id: 694.a8c Suspend: 1 Teb: 7ff93000 Unfrozen
  22  Id: 694.ad4 Suspend: 1 Teb: 7ff92000 Unfrozen
  23  Id: 694.1098 Suspend: 1 Teb: 7ff2f000 Unfrozen
  24  Id: 694.b08 Suspend: 1 Teb: 7ff2e000 Unfrozen
  25  Id: 694.19c Suspend: 1 Teb: 7ff90000 Unfrozen
  26  Id: 694.fcc Suspend: 1 Teb: 7ff2d000 Unfrozen
  27  Id: 694.764 Suspend: 1 Teb: 7ff91000 Unfrozen
  28  Id: 694.1334 Suspend: 1 Teb: 7ff2b000 Unfrozen

。。。线程也这么少,怎么办

还是不死心。从上面的DLL看到,程序中的模块要么系统的,要么CLR的,没有COM/COM+,问题应该还是在CLR相关的东西上。于是用!eeheap –loader看看loader heap的大小:

0:000> !eeheap -loader
Loader Heap:
--------------------------------------
System Domain: 7a38f918
LowFrequencyHeap: Size: 0x0(0)bytes.
HighFrequencyHeap: 02e72000(8000:1000) Size: 0x1000(4096)bytes.
StubHeap: 02e7a000(2000:2000) 1b5b0000(10000:4000) Size: 0x6000(24576)bytes.
Virtual Call Stub Heap:
  IndcellHeap: Size: 0x0(0)bytes.
  LookupHeap: Size: 0x0(0)bytes.
  ResolveHeap: Size: 0x0(0)bytes.
  DispatchHeap: Size: 0x0(0)bytes.
  CacheEntryHeap: Size: 0x0(0)bytes.
Total size: 0x7000(28672)bytes
--------------------------------------
Shared Domain: 7a38fef0
LowFrequencyHeap: 02ea0000(2000:1000) 1b6d0000(10000:d000) Size: 0xe000(57344)bytes.
Wasted: 0x1000(4096)bytes.
HighFrequencyHeap: 02ea2000(8000:5000) Size: 0x5000(20480)bytes.
StubHeap: 02eaa000(2000:1000) 1bc80000(10000:1000) Size: 0x2000(8192)bytes.
Wasted: 0x1000(4096)bytes.
Virtual Call Stub Heap:
  IndcellHeap: 02eb0000(2000:1000) Size: 0x1000(4096)bytes.
  LookupHeap: 02eb5000(2000:1000) Size: 0x1000(4096)bytes.
  ResolveHeap: 02ebb000(5000:5000) 1bc10000(10000:2000) Size: 0x7000(28672)bytes.
  DispatchHeap: 02eb7000(4000:3000) Size: 0x3000(12288)bytes.
  CacheEntryHeap: 02eb2000(3000:1000) Size: 0x1000(4096)bytes.
Total size: 0x21000(135168)bytes
--------------------------------------
Domain 1: ded80
LowFrequencyHeap: 02e80000(2000:1000) Size: 0x1000(4096)bytes.
HighFrequencyHeap: 02e82000(8000:4000) Size: 0x4000(16384)bytes.
StubHeap: Size: 0x0(0)bytes.
Virtual Call Stub Heap:
  IndcellHeap: Size: 0x0(0)bytes.
  LookupHeap: Size: 0x0(0)bytes.
  ResolveHeap: Size: 0x0(0)bytes.
  DispatchHeap: Size: 0x0(0)bytes.
  CacheEntryHeap: Size: 0x0(0)bytes.
Total size: 0x5000(20480)bytes
--------------------------------------
Domain 2: 113b60
LowFrequencyHeap: 1b550000(2000:2000) 1b760000(10000:f000) 1b830000(10000:10000) 1bcd0000(10000:f000) 1c150000(10000:10000) 1c260000(10000:10000) 1c300000(10000:10000) 1c380000(10000:10000) 1c430000(10000:10000) 1c510000(10000:10000) 1c5c0000(10000:10000) 1c6b0000(10000:10000) 1c750000(10000:10000) 1c800000(10000:f000) 1c8b0000(10000:f000) 1c920000(10000:10000) ……
1db30000(10000:f000) 1dbc0000(10000:f000) 1dca0000(10000:f000) 1dd50000(10000:10000) 1de00000(10000:10000) 1de90000(10000:10000) 1df40000(10000:10000) 1dfb0000(10000:10000) 1df90000(10000:f000) 1e0e0000(10000:f000) 1e180000(10000:10000) 1e230000(10000:10000) 1e2d0000(10000:10000) 1e370000(10000:10000) 1e420000(10000:f000) 1e4b0000(10000:f000) 1e550000(10000:f000) 1e600000(10000:10000) 1e6b0000(10000:10000) 1e740000(10000:10000) 1e7f0000(10000:10000) 1e8e0000(10000:10000) 1eb60000(10000:f000) 1ec10000(10000:f000) 1ed30000(10000:10000) 1eda0000(10000:10000) 1ee40000(10000:c000) Size: 0x447000(4485120)bytes.
Wasted: 0x17000(94208)bytes.
HighFrequencyHeap: 1b552000(8000:8000) 1b820000(10000:f000) 1bb80000(10000:10000) 1c120000(10000:10000) 1c230000(10000:f000) 1c2d0000(10000:10000) 1c390000(10000:10000) 1c460000(10000:10000) 1c570000(10000:10000) 1c610000(10000:10000) 1c720000(10000:f000) 1c7d0000(10000:10000) ……
1dd20000(10000:10000) 1ddf0000(10000:10000) 1dea0000(10000:10000) 1df20000(10000:f000) 1df30000(10000:10000) 1e080000(10000:10000) 1e150000(10000:10000) 1e220000(10000:10000) 1e2e0000(10000:10000) 1e3b0000(10000:f000) 1e450000(10000:10000) 1e500000(10000:10000) 1e5d0000(10000:10000) 1e6a0000(10000:10000) 1e750000(10000:10000) 1e860000(10000:f000) 1e910000(10000:10000) 1ebb0000(10000:10000) 1ec80000(10000:10000) 1ed90000(10000:10000) 1ee50000(10000:9000) Size: 0x3b8000(3899392)bytes.
Wasted: 0x9000(36864)bytes.
StubHeap: 1b55a000(2000:1000) Size: 0x1000(4096)bytes.
Virtual Call Stub Heap:
  IndcellHeap: 1b5a0000(3000:1000) Size: 0x1000(4096)bytes.
  LookupHeap: 1b5a6000(3000:1000) Size: 0x1000(4096)bytes.
  ResolveHeap: 1b5ac000(4000:1000) Size: 0x1000(4096)bytes.
  DispatchHeap: 1b5a9000(3000:1000) Size: 0x1000(4096)bytes.
  CacheEntryHeap: 1b5a3000(3000:1000) Size: 0x1000(4096)bytes.
Total size: 0x804000(8404992)bytes
--------------------------------------
Jit code heap:
LoaderCodeHeap: 1ee10000(10000:c000) Size: 0xc000(49152)bytes.
LoaderCodeHeap: 1ed60000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1ebe0000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1e8d0000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1e7a0000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1e690000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1e5a0000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1e4a0000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1e3a0000(10000:10000) Size: 0x10000(65536)bytes.
……
LoaderCodeHeap: 1cb70000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1ca50000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1c980000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1c870000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1c780000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1c640000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1c540000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1c400000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1c330000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1c1c0000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1bce0000(10000:10000) Size: 0x10000(65536)bytes.
LoaderCodeHeap: 1bc70000(10000:1000) Size: 0x1000(4096)bytes.
HostCodeHeap: 1bc60000 Size: 0xa000(40960)bytes.
LoaderCodeHeap: 1b7d0000(10000:10000) Size: 0x10000(65536)bytes.
Total size: 0x2d7000(2977792)bytes
--------------------------------------
Module Thunk heaps:
Module 50224000: Size: 0x0(0)bytes.
Module 505c4000: Size: 0x0(0)bytes.
Module 648ec000: Size: 0x0(0)bytes.
Module 6638c000: Size: 0x0(0)bytes.
Module 7a71e000: Size: 0x0(0)bytes.
Module 502c2000: Size: 0x0(0)bytes.
Module 790c2000: Size: 0x0(0)bytes.
Module 02ea2380: Size: 0x0(0)bytes.
Module 02ea2010: Size: 0x0(0)bytes.
……
Module 1ed9705c: Size: 0x0(0)bytes.
Module 1ed9a884: Size: 0x0(0)bytes.
Module 1ed9e0ac: Size: 0x0(0)bytes.
Module 1ee51944: Size: 0x0(0)bytes.
Module 1ee5516c: Size: 0x0(0)bytes.
Total size: 0x0(0)bytes
--------------------------------------
Module Lookup Table heaps:
Module 50224000: Size: 0x0(0)bytes.
Module 505c4000: Size: 0x0(0)bytes.
Module 648ec000: Size: 0x0(0)bytes.
Module 6638c000: Size: 0x0(0)bytes.
Module 7a71e000: Size: 0x0(0)bytes.
Module 502c2000: Size: 0x0(0)bytes.
Module 790c2000: Size: 0x0(0)bytes.
Module 02ea2380: Size: 0x0(0)bytes.
Module 02ea2010: Size: 0x0(0)bytes.
Module 69670000: Size: 0x0(0)bytes.
……
Module 639ea000: Size: 0x0(0)bytes.
Module 50d5a000: Size: 0x0(0)bytes.
Module 653b4000: Size: 0x0(0)bytes.
Module 02ea27cc: Size: 0x0(0)bytes.
Module 1ed9705c: Size: 0x0(0)bytes.
Module 1ed9a884: Size: 0x0(0)bytes.
Module 1ed9e0ac: Size: 0x0(0)bytes.
Module 1ee51944: Size: 0x0(0)bytes.
Module 1ee5516c: Size: 0x0(0)bytes.
Total size: 0x0(0)bytes
--------------------------------------
Total LoaderHeap size: 0xb08000(11567104)bytes

=======================================

上面只是!eeheap –loader输出的5%左右。从上面的输出来看,loader heap占用了11MB的内存。这个数字没问题,问题在于这个module list上面。这里成千上万的module,势必导致内存碎片。
前面lmvm命令可以检查加载的module。但是lmvm命令工作方式是Win32层面的。如果DLL通过LoadLibrary起来的,这个命令能看到。但是CLR的动态DLL,除了使用LoadLibrary外,CLR还可以直接用MapViewOfFile的方法直接把DLL弄到内存中操作。这种情况lmvm就没把法了。所以需要用!eeheap –loader从CLR层面检查。
除了!eeheap外,用!dumpdomain命令,也可以从CLR层面列举出所有的assembly,包括动态的和静态的。
找到内存碎片的原因后,接下来就是分析这些碎片的来源了。既然这里是module,那随便挑一个,用!dumpmodule检查详细信息:
0:000> !dumpmodule -mt 1ee5516c
Name: cplxobsw, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Attributes: PEFile
Assembly: 1e929530
LoaderHeap: 00000000
TypeDefToMethodTableMap: 1ee47f18
TypeRefToMethodTableMap: 1ee47fe4
MethodDefToDescMap: 1ee48058
FieldDefToDescMap: 1ee484f4
MemberRefToDescMap: 1ee486e8
FileReferencesMap: 1ee488a4
AssemblyReferencesMap: 1ee488a8
MetaData start address: 1ee8be8c (49668 bytes)

Types defined in this module

      MT    TypeDef Name
------------------------------------------------------------------------------
1ee57e5c 0x02000002 Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap
1ee587ac 0x02000003 Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderI_UAC_WSSoap
1ee55844 0x02000004 Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializer1
1ee56fac 0x02000005 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer
1ee5745c 0x02000006 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer1
1ee579d4 0x02000007 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer2
1ee575ec 0x02000008 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer3
1ee55e7c 0x02000009 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer4
1ee559cc 0x0200000a Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer5
1ee55b5c 0x0200000b Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer6
1ee57a9c 0x0200000c Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer7
1ee55db4 0x0200000d Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer8
1ee56714 0x0200000e Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer9
1ee5777c 0x0200000f Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer10
1ee57524 0x02000010 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer11
1ee56d54 0x02000011 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer12
1ee57844 0x02000012 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer13
1ee568a4 0x02000013 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer14
1ee576b4 0x02000014 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer15
1ee55a94 0x02000015 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer16
1ee55cec 0x02000016 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer17
1ee57204 0x02000017 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer18
1ee5619c 0x02000018 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer19
1ee5632c 0x02000019 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer20
1ee55f44 0x0200001a Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer21
1ee572cc 0x0200001b Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer22
1ee57c2c 0x0200001c Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer23
1ee55c24 0x0200001d Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer24
1ee56c8c 0x0200001e Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer25
1ee567dc 0x0200001f Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer26
1ee56e1c 0x02000020 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer27
1ee56584 0x02000021 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer28
1ee56a34 0x02000022 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer29
1ee5713c 0x02000023 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer30
1ee5600c 0x02000024 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer31
1ee57074 0x02000025 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer32
1ee560d4 0x02000026 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer33
1ee564bc 0x02000027 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer34
1ee5696c 0x02000028 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer35
1ee57394 0x02000029 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer36
1ee56ee4 0x0200002a Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer37
1ee563f4 0x0200002b Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer38
1ee56264 0x0200002c Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer39
1ee56afc 0x0200002d Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer40
1ee56bc4 0x0200002e Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer41
1ee5790c 0x0200002f Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer42
1ee5664c 0x02000030 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer43
1ee57b64 0x02000031 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer44
1ee55904 0x02000032 Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer45
1ee5575c 0x02000033 Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract

Types referenced in this module

      MT    TypeRef Name
------------------------------------------------------------------------------
63a191a4 0x01000001 System.Xml.Serialization.XmlSerializationWriter
63a18ac0 0x01000002 System.Xml.Serialization.XmlSerializationReader
63a19804 0x01000003 System.Xml.Serialization.XmlSerializer
63a19798 0x01000004 System.Xml.Serialization.XmlSerializerImplementation
1bb88e8c 0x01000005 t_UserInfo
639f2988 0x01000006 System.Xml.XmlReader
790fd8b4 0x01000007 System.Collections.Hashtable
790ffe7c 0x01000008 System.Type
790f9244 0x0100000e System.String
790fdb60 0x0100000f System.Int32
639f3758 0x01000010 System.Xml.XmlConvert
790f8a7c 0x01000014 System.Object
79103c00 0x01000019 System.Boolean
639f59e0 0x0100001a System.Xml.XmlQualifiedName
639fa358 0x0100001b System.Xml.XmlNameTable


上面的输入就非常明显了。程序明显是在做XmlSerialization。接下来看看是在Serialize什么类型的object,有了这个信息后,去看源代码就更有方向了.随便找一个method table来看:


0:000> !dumpmt -md 1ee57e5c
EEClass: 1ee4b428
Module: 1ee5516c
Name: Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap
mdToken: 02000002  (cplxobsw, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null)
BaseSize: 0x44
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 53
--------------------------------------
MethodDesc Table
   Entry MethodDesc      JIT Name
7934cdcc   79137ab8   PreJIT System.Object.ToString()
7934bba0   79137ac0   PreJIT System.Object.Equals(System.Object)
7934bb90   79137ad8   PreJIT System.Object.GetHashCode()
793424c0   79137ae0   PreJIT System.Object.Finalize()
1ee5802d   1ee57e38     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.InitCallbacks()
1ee57f61   1ee57cc0     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write3_UserReg(System.Object[])
1ee57f65   1ee57cc8     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write4_UserRegResponse(System.Object[])
1ee57f69   1ee57cd0     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write5_UserRegSimple(System.Object[])
1ee57f6d   1ee57cd8     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write6_UserRegSimpleResponse(System.Object[])
1ee57f71   1ee57ce0     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write7_UserRegPhone(System.Object[])
1ee57f75   1ee57ce8     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write8_UserRegPhoneResponse(System.Object[])
1ee57f79   1ee57cf0     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write9_ModifyUserInfo(System.Object[])
1ee57f7d   1ee57cf8     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write10_ModifyUserInfoResponse(System.Object[])
1ee57f81   1ee57d00     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write11_UserLogin(System.Object[])
1ee57f85   1ee57d08     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write12_UserLoginResponse(System.Object[])
1ee57f89   1ee57d10     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write13_UserLogout(System.Object[])
1ee57f8d   1ee57d18     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write14_UserLogoutResponse(System.Object[])
1ee19d80   1ee57d20      JIT Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write15_GetUserInfo(System.Object[])
1ee57f95   1ee57d28     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write16_GetUserInfoResponse(System.Object[])
1ee57f99   1ee57d30     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write17_FindUser(System.Object[])
1ee57f9d   1ee57d38     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write18_FindUserResponse(System.Object[])
1ee57fa1   1ee57d40     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write19_FindUserEx(System.Object[])
1ee57fa5   1ee57d48     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write20_FindUserExResponse(System.Object[])
1ee57fa9   1ee57d50     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write21_ModifyPassword(System.Object[])
1ee57fad   1ee57d58     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write22_ModifyPasswordResponse(System.Object[])
1ee57fb1   1ee57d60     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write23_ResetPassword(System.Object[])
1ee57fb5   1ee57d68     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write24_ResetPasswordResponse(System.Object[])
1ee57fb9   1ee57d70     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write25_ModifyPasswordPhone(System.Object[])
1ee57fbd   1ee57d78     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write26_ModifyPasswordPhoneResponse(System.Object[])
1ee57fc1   1ee57d80     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write27_CheckUserToken(System.Object[])
1ee57fc5   1ee57d88     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write28_CheckUserTokenResponse(System.Object[])
1ee57fc9   1ee57d90     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write29_SetUserStatus(System.Object[])
1ee57fcd   1ee57d98     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write30_SetUserStatusResponse(System.Object[])
1ee57fd1   1ee57da0     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write31_ActivateUser(System.Object[])
1ee57fd5   1ee57da8     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write32_ActivateUserResponse(System.Object[])
1ee57fd9   1ee57db0     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write33_AppActivateUser(System.Object[])
1ee57fdd   1ee57db8     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write34_AppActivateUserResponse(System.Object[])
1ee57ff1   1ee57dc0     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write35_GetUserLoginHistory(System.Object[])
1ee57ff5   1ee57dc8     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write36_GetUserLoginHistoryResponse(System.Object[])
1ee57ff9   1ee57dd0     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write37_GetUnactiveUserNumber(System.Object[])
1ee57ffd   1ee57dd8     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write38_GetUnactiveUserNumberResponse(System.Object[])
1ee58001   1ee57de0     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write39_GetTtlUserNumber(System.Object[])
1ee58005   1ee57de8     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write40_GetTtlUserNumberResponse(System.Object[])
1ee58009   1ee57df0     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write41_GetActiveUserNumber(System.Object[])
1ee5800d   1ee57df8     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write42_GetActiveUserNumberResponse(System.Object[])
1ee58011   1ee57e00     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write43_DailyRegisterCount(System.Object[])
1ee58015   1ee57e08     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write44_DailyRegisterCountResponse(System.Object[])
1ee58019   1ee57e10     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write45_GetDailyReport(System.Object[])
1ee5801d   1ee57e18     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write46_GetDailyReportResponse(System.Object[])
1ee58021   1ee57e20     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write47_Test(System.Object[])
1ee58025   1ee57e28     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write48_TestResponse(System.Object[])
1ee19eb8   1ee57e30      JIT Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap.Write2_t_UserInfo(System.String, System.String, t_UserInfo, Boolean, Boolean)
1ee58031   1ee57e40     NONE Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterI_UAC_WSSoap..ctor()

从上面的输出中,就能看到序列化类型的方法。有了这些方法,查找序列化的来源就容易多了。

有了这些信息后,开发人员很容易地定位到问题跟WCF调用相关。实现WCF的时候选择了XML序列化方法。在下面这个blog的评论中,有人批评WCF XML序列化会导致这样的问题:
http://blogs.msdn.com/tess/archive/2006/02/15/net-memory-leak-xmlserializing-your-way-to-a-memory-leak.aspx

这个问题在这里已经非常明显了。当然dump中还有其它可以挖掘的地方。比如用!dumpheap –stat看看CLR object的数量。用!dumpheap –mt寻找一些序列化object的地址,然后用!gcroot看看序列化object的引用关系。或者用!finalizequeue看看是否堆积了大量的object等待Dispose。由于篇幅的关系,这些细枝末节就不列举了。

总的说来,!eeheap –gc隔离问题到loader heap和dynamic module, !dumpmodule –mt找到引发序列化的类型,!dumpmt –md找出类型的详细信息。三个命令就可以隔离出问题。
该问题最后通过WCF object pool的方法缓存WCF client proxy,解决问题。

posted @ 2007-10-26 11:20 lixiong 阅读(2808) | 评论 (17)编辑

handle leak ts steps in chinese


1. 安装Windbg到C:\Debuggers目录
2. 安装Application Verifier。对需要调试的程序激活“Handles - Detect invalid handle usage”
3. 确保编译的时候生成了目标程序的symbol文件,并且统一部署到自定义的symbol目录。
4. 启动目标程序
5. 启动性能监视器开始监视目标程序,添加
Process
Processor
Memory
System
6. 启动windbg,设定好symbol路径,开始监视目标程序
7. 在windbg命令窗口输入:
.logopen c:\log.txt
记录windbg输出到文本文件
8. 运行!handle和!htrace命令,等待命令执行完成
9. 输入下列命令避免1st chance exception干扰问题的重现
SXN *
SXN av
SXN clr
SXN eh
SXN cc
10. 输入g命令,让目标程序开始运行
11. 重现问题,问题发生后用windbg挂起程序
12. 再次输入!handle和!htrace,保存handle信息
13. 运行.dump命令抓取问题发生后的dump文件
14. 输入.logclose关闭log文件
15. 收集性能日志文件

通过分析C:\log.txt文件中问题发生前后的差异,找到发生泄漏的handle是在什么callstack中分配的,以及handle的类型。在结合源代码定位。

posted @ 2006-11-06 14:16 lixiong 阅读(889) | 评论 (5)编辑

除了memory leak和handle leak外的其它资源泄露

 

除了memory leakhandle外,其它类型的资源泄露还有GDI Leakdesktop heap high usage

 

关于GDI Leak,可以参考:

 

Detect and Plug GDI Leaks in Your Code with Two Powerful Tools for Windows XP

http://msdn.microsoft.com/msdnmag/issues/03/01/GDILeaks/default.aspx

 

Resource Leaks: Detecting, Locating, and Repairing Your Leaky GDI Code

http://msdn.microsoft.com/msdnmag/issues/01/03/leaks/default.aspx

 

Desktop heap是一类特殊的内存。下面这些kb对此有一些描述:

 

PRB: User32.dll or Kernel32.dll fails to initialize

http://support.microsoft.com/kb/184802/en-us

 

"Out of Memory" error message appears when you have a large number of programs running

http://support.microsoft.com/kb/126962/en-us

support.microsoft.com 上搜索desktop heap,可以找到更多的信息。Windows除了使用进程来管理资源外,还是用Sessiondesktop来管理资源。比如只有在同一个Session里面的进程才可以共享剪贴板数据,Windows Message只能在属于同一个desktop的进程之间传递。而desktop heap,是操作系统管理的,为不同session创建的,由同一session内所有desktop共享的内存。当创建进程,创建GUI的时候,都会消耗desktop heap。当Desktop Heap用光后,系统中各种莫名其妙的问题就会发生。比如无法创建新进程,无法弹出菜单,API调用会莫名其妙地出错。

 

Desktop heap用光的原因往往是太多进程同时运行,或者创建了太多GUI object。怀疑是Desktop heap相关问题的时候,首先可以用下面这篇文章的方法来检查是否Desktop heap用光:

 

A new System log entry is not generated if the desktop heap is exhausted in Microsoft Windows 2000

http://support.microsoft.com/kb/810807/en-us

 

如果确认是desktop heap问题后,检察系统是否有太多进程在同时运行,(我曾经见过一百多个dllhost进程同时运行的情况),或者某一程序有特殊的GUI操作。在优化系统,优化代码后,如果的确需要使用很多desktop heap,可以参考前面的kb改变注册表来做调整。

 

除了上面这些系统资源外,还有其它很多资源都可能出现问题,比如TCP Port用光。

 

When you try to connect from TCP ports greater than 5000 you receive the error 'WSAENOBUFS (10055)'

http://support.microsoft.com/kb/196271/en-us

 

如果排错只是按部就班的操作,排错就不是一项有趣的工作了。

posted @ 2006-11-05 11:13 lixiong 阅读(1715) | 评论 (0)编辑

一些重要的计数器

一些重要的计数器

 

解决性能问题的时候,我往往会让客户添加下面一些计数器进行性能收集。

 

Process object下的所有计数器。

Processor object下的所有计数器

System object下的所有计数器

Memory object下的所有计数器

 

如果客户的程序是.NET程序,还会添加 .NET 开头的object下的所有技术其

如果客户使用ASP.NET,还会添加 ASP.NET 开头的object下的所有技术其

 

分析性能日志的时候,我会重点观察下面这些计数器

 

Process object

Process object中的计数器可以针对目标进程分析内存,CPU,线程数目和handle数目。首先要确定目标进程,然后分析目标进程的下面一些计数器:

 

% Processor Time

该计数器是该进程占用CPU资源的指标。当进程繁忙的时候,CPU平均占用率应该在80%以内。如果超过该数值,程序可以认为发生了high CPU的问题。另外一种问题是CPU波动幅度大。虽然平均占用率不高,但是上下跳动频繁。在某一个短时间段里面,会有连续高CPU的情况出现。

 

Handle Count

该计数器记录了当前进程使用的kernel object handle数量。Kernel object是重要的系统资源。当程序进入稳定运行状态的时候,Handle Count数量也应该维持在一个稳定的区间。如果发现Handle Count在整个程序周期内总体趋势是连续向上,可以考虑程序是否有Handle Leak

 

ID Process

该计数器记录了目标进程的进程ID。你可能觉得奇怪,ID有什么好观察的。进程ID是用来观察程序是否有重启发生。比如ASP.NET工作进程可能会自动回收。由于进程名都相同,只有通过进程ID来判断是否进程有重新启动现象。如果ID有变化,考虑程序是否发生崩溃或者Recycle

 

Private Bytes

该计数器记录了当前通过VirtualAlloc API CommitMemory数量。无论是直接调用API申请的内存,被Heap Manager申请的内存,或者是CLR managed heap,都算在里面。跟Handle Count一样,如果在整个程序周期内总体趋势是连续向上,说明有Memory Leak

 

Virtual Bytes

该计数器记录了当前进程申请成功的用户态总内存地址,包括DLL/EXE占用的地址和通过VirtualAlloc API ReserveMemory Space数量,所以该计数器应该总大于Private Bytes。一般来说,Virtual BytesPrivate Bytes的变化大致一致。由于内存分片的存在, Virtual BytesPrivate Byes一般保持一个相对稳定的比例关系。当Virtual BytesPrivate Bytes的比例关系大于2的时候,程序往往有比较严重的内存地址分片。

 

Processor object

Processor object记录系统中芯片的负载情况。由于普通程序并不刻意邦定到某个具体CPU上执行,所以在多CPU机器上观察Total Instance也就足够了

 

% Processor Time 该计数器跟Process下的% Processor Time的意义一样,不过这里记录的是所有进程带来的芯片,而不是针对具体某一个进程。通过把这个计数器跟Process下的同名计数器一起比较,就能看出系统的高CPU问题是否是由于单一的某个进程导致的

 

System

System object记录系统中一个整体的统计信息。所以不区分Instance. 通过比较System object下的counter和其他counter的变化趋势,往往能看出一些线索

 

Context Switch/sec

Context Switch标示了系统中整体线程的调度,切换频率。线程切换是开销比较大的操作。频繁的线程切换导大量CPU周期被浪费。所以看到高CPU的时候,一定要跟Context Switch一起比较。如果两者有相同的变化趋势,高CPU往往是由于contention导致的,而不是死循环。

 

Exception Dispatches/sec

Exception Dispatches表示了系统中异常派发,处理的频繁程序。跟线程切换一样,异常处理也需要大量的CPU开销。分析方法跟Context Switch雷同。

 

File Data Operations/sec

File Data Operations记录了当前系统中磁盘文件读写的频繁程度。通过观察该计数器跟其他性能指标的变化趋势,通常能够判断磁盘文件操作是否是性能瓶颈。类似的计数器还有Network Interface\Bytes total/sec

 

Memory

Memory object记录了当前系统中整体内存的统计信息。

 

Available Mbytes

Committed Bytes

Available Mbytes记录了当前剩余的物理内存数量。Committed Bytes记录了所有进程commit的内存数量。结合两个计数器可以观察到:

1)     两者相加可以粗略估计系统总体可用内存多少,便于估计物理配置

2)     Available Mbytes少于100MB的时候,说明系统总体内存吃紧,会影响到整个系统所有进程的性能。应该考虑增加物理内存或者监察内存泄露

3)     通过比较Process\Private BytesVirtual Bytes,便于进一步确认是否有内存泄露,判断内存泄露是否是某一单个进程导致

 

Free System Page Table EntriesPool Paged BytesPool Paged Bytes

这三个计数器可以衡量核心态空闲内存的数量。特别是当使用/3GB开关后,核心态内存地址被压缩,容易导致核心态内存不足,继而引发一些非常妖怪的问题。可以参考前面提到的文章:

How to use the /userva switch with the /3GB switch to tune the User-mode space to a value between 2 GB and 3 GB

http://support.microsoft.com/kb/316739/en-us

 

.NET CLR Memory

.NET CLR Memory object记录了CLR进程中跟CLR相关的内存信息。该类别下的所有计数器都很有意思,而且意思也非常直接。建议用一个例子程序进行测试和研究。下面是两个最常用的计数器

 

Bytes in all heaps

Bytes in all heaps记录了上次GC发生时候所统计到的,进程中不能被回收的所有CLR object占用的内存空间。该计数器不是实时的,每次GC发生的时候该计数器才更新。跟同一进程的Process\Private bytes比较,可以区分出managed heapnative memory的变化情况。对于memory leak,便于区分是managed heapleak还是native memoryleak

 

%Time in GC

%Time in GC记录了GC发生的频繁程度。一般来说15%以内算比较正常。当超过20%说明GC发生过于频繁。由于GC不仅仅带来很高的CPU开销,还需要挂起目标进程的CLR线程,所以高频率GC是非常危险的。通过跟CPU利用率和其他性能指标比较,往往能够看出GC对性能的影响。高频率的GC往往因为

1)     负载过高

2)     不合理的架构,对内存使用效率不高

3)     内存泄露,内存分片导致内存压力

 

如果目标程序是ASP.NET,在ASP.NET开头的object中,下面这些计数器对于测量ASP.NET的性能非常有用。由于不少计数器存在于多个object类别中,下面只列出具体的计数器名字,而不去对应到具体的object:

 

Application Restarts

Application Restarts记录了ASP.NET Application Domain重启的次数。导致ASP.NET appDomain重启的原因往往是虚拟目录中被修改。比如修改了web.config文件,或者防毒程序对虚拟目录进行扫描。通过该计数器可以观察是否有异常的重启现象

 

Request Execution time

Request Execution time记录了请求的执行时间,是衡量ASP.NET性能的最直接参数。通过该计数器的平均值来衡量性能是否合乎预期值。需要注意的地方是由于Windows并非实时系统,所以不能用峰值来衡量整体性能。比如当GC发生的时候,请求执行时间肯定都要超过GC的时间。所以平均值才是有效的标准

 

Request Current

Request Current记录了当前正在处理的和等待处理的请求。最理想的情况是Request Current等于CPU的数量,这说明请求跟硬件资源能并发处理的能力恰好吻合,硬件投资正运行在最优状态。但是一般说来,当负荷比较大的时候,Request Current也随着增高。如果Request Current在一段时间内有超过10的情况,说明性能有问题。注意观察这个时候对应的CPU情况和其他的资源。如果CPU不高,很可能是程序中有blocking发生,比如等待数据库请求,导致请求无法及时完成。

 

Request/second

Request/second计数器记录了每秒钟到达ASP.NET的请求数。这是衡量ASP.NET负载的直接参数。注意观察Request/second是否超过程序的预期吞吐量。如果Request/Second有突发的波动,注意看是否有拒绝服务攻击。通过把Request/second,Request Current, Request Execution time和系统资源一起比较,往往能够看出来ASP.NET整体性能的变化和各个因素之间的影响

 

Request in Application Queue

ASP.NET没有空余的工作线程来处理新进入的请求的时候,新的请求会被放到Application Queue中。当Application Queue堆积的请求也超过设定数值的时候,ASP.NET直接返回503 Server too busy错误,同时丢弃该请求。所以正常情况下,Request in Application Queue应该总为0,否则说明已经有请求堆积,性能问题严重

posted @ 2006-11-05 01:23 lixiong 阅读(2633) | 评论 (3)编辑

IE的leak

     摘要: IE的memory leak, 带demo和分析,介绍如何排查native memory leak,debug paper的一部分。  阅读全文

posted @ 2006-10-24 22:53 lixiong 阅读(2462) | 评论 (10)编辑

useful log options in .Net

这个要整理出来,别忘了

posted @ 2006-10-13 10:17 lixiong 阅读(466) | 评论 (3)编辑

Mixed DLL Loading analysis

     摘要: 这是一个mixed dll loading导致deadlock的典型例子。合理利用dump+windbg+sos其实还是比较容易能定位问题的  阅读全文

posted @ 2006-09-21 00:43 lixiong 阅读(1810) | 评论 (3)编辑