2006年9月21日
#
摘要: 目前我们在开发和测试Win7下面的活动目录管理工具,用WPF写的。测试方面的三大重要任务:
1. 因为我们的产品是跟在Win7里面的,所以编译,发布流程是跟着Windows的走。换句话说,每次测试新版本都需要重新装刚刚编译出来的Windows 7。其次,活动目录不是一个机器就可以了,要搭建多个服务器节点(DC)。所以如何高效自动地完成测试环境的搭建是很有挑战的
2. 完成WPF程序的自动化测试。简单地说,就是要通过代码去模拟用户的UI操作。比如点鼠标,输入数据,点确定按钮等等。大家排排脑袋想下这个事情的难度。比如给你一个WPF写的计算器,你知道怎么做么?如何写出高效,稳定和全面的UI自动化也是很有挑战的
3. 熟悉活动目录。熟悉活动目录的就知道这个东西有多复杂。当然不熟悉的也没关系,不能指望一个人什么都知道
我们招人的目的就是做好上面三点工作。技术方面的话,能搞定C#和Windows就可以了。搞定的意思是指能搞定技术细节,比如:
......
阅读全文
《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。如果您的分享能够帮助其它读者,我非常希望能够送书给您作为答谢。
如果您对书中所述内容有疑惑,也欢迎您写信来讨论。我会尽快回复。如果我们之间的讨论对其他读者有帮助,我也会放到网上,同时送书给您作为答谢。
最近一位朋友的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,解决问题。
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的类型。在结合源代码定位。
除了memory leak和handle外,其它类型的资源泄露还有GDI Leak和desktop 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除了使用进程来管理资源外,还是用Session和desktop来管理资源。比如只有在同一个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
如果排错只是按部就班的操作,排错就不是一项有趣的工作了。
一些重要的计数器
解决性能问题的时候,我往往会让客户添加下面一些计数器进行性能收集。
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 Commit的Memory数量。无论是直接调用API申请的内存,被Heap Manager申请的内存,或者是CLR 的managed heap,都算在里面。跟Handle Count一样,如果在整个程序周期内总体趋势是连续向上,说明有Memory Leak
Virtual Bytes
该计数器记录了当前进程申请成功的用户态总内存地址,包括DLL/EXE占用的地址和通过VirtualAlloc API Reserve的Memory Space数量,所以该计数器应该总大于Private Bytes。一般来说,Virtual Bytes跟Private Bytes的变化大致一致。由于内存分片的存在, Virtual Bytes跟Private Byes一般保持一个相对稳定的比例关系。当Virtual Bytes跟Private 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 Bytes跟Virtual Bytes,便于进一步确认是否有内存泄露,判断内存泄露是否是某一单个进程导致
Free System Page Table Entries,Pool Paged Bytes和Pool 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 heap和native memory的变化情况。对于memory leak,便于区分是managed heap的leak还是native memory的leak
%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,否则说明已经有请求堆积,性能问题严重
摘要: IE的memory leak, 带demo和分析,介绍如何排查native memory leak,debug paper的一部分。
阅读全文
摘要: 这是一个mixed dll loading导致deadlock的典型例子。合理利用dump+windbg+sos其实还是比较容易能定位问题的
阅读全文