在企业用户环境里,.NET Serviced Component使用广泛。它比较好的把传统COM+封装和.NET应用逻辑衔接了起来,在服务器端应用起到重要作用。.NET Serviced Component 的使用需要注意到很多方面,特别是要做到对象资源合理应用(pooling)和及时释放(Dispose)。现有文章就这方面有很多具体讨论

在这里,我要分析的是一种以前处理过的特定情况下.NET Serviced Component的引发的High CPU的问题。不只一个客户遇到此类问题,觉得有必要和大家分享一下。

如果程序出现High CPU,这个应用程序线程一定出现了繁忙的运算,比如重复的计算或者长时间的循环,而不是等待数据库,锁,或其它资源。如果这个程序是.NET程序,频繁Garbage Collection导致High CPU就必须要重点考虑。因为每次GC都需要检查.NET 对象树和调整.NET堆, 是繁重的操作。我们可以通过捕捉性能日志(perfmon),查看.NET CLR Memory 对象下的%Time in GC 和 Induced GC 这两个性能计数器指标,来判断High CPU是不是和GC有关。

在这个例子里面,通过查看性能监视器,可以看到Induced GC增长非常的快速,表明是这次High CPU的直接原因:

通常情况下,Induced GC 出现是客户代码里面直接调用了GC.Collect 。然而,在查看客户代码后,发现根本没有GC.Collect出现。

我们注意到这个程序里面使用了.NET Enterprise Serviced Components, 开始便建议客户使用Dispose方法释放这些Components, 而不是用DisposeObject:

http://msdn.microsoft.com/en-us/library/system.enterpriseservices.servicedcomponent.disposeobject.aspx

并且尝试启用对象池,, 发现改善并不明显:

http://www.codeproject.com/Articles/579/COM-Object-Pooling

http://msdn.microsoft.com/en-us/library/windows/desktop/ms684273(v=vs.85).aspx

于是在这个程序High CPU的时候抓取了Memory Dump。

注:抓取Memory Dump的方法很多,可以用WinDBG, procdump或者DebugDiag

通过仔细分析Memory Dump,发现Induced GC逻辑出现在以下Call Stack里面:

非托管 Call Stack:

Child-SP          RetAddr           Call Site
`0f59bbe8 `7704ce00 ntdll!ZwWaitForSingleObject+0xa
`0f59bbf0 000007fe`f52fa74a kernel32!WaitForSingleObjectEx+0x9c
`0f59bcb0 000007fe`f52fa83b mscorwks!CLREventWaitHelper+0x42
`0f59bd10 000007fe`f53cee38 mscorwks!CLREvent::WaitEx+0x63
`0f59bdc0 000007fe`f53c1cb7 mscorwks!SVR::gc_heap::wait_for_gc_done+0x88
`0f59be00 000007fe`f542913b mscorwks!SVR::GCHeap::GarbageCollectGeneration+0x147
`0f59be90 000007fe`f5412ac3 mscorwks!SVR::GCHeap::GarbageCollect+0x5b
`0f59bee0 000007fe`f57301a5 mscorwks!GCInterface::AddMemoryPressure+0x13b
`0f59bf70 000007fe`f57b9beb mscorwks!RCW::AddMemoryPressure+0x15
`0f59bfb0 000007fe`f57dbbf4 mscorwks!RCW::CreateRCW+0x17b
`0f59c030 000007fe`f57dbdea mscorwks!COMInterfaceMarshaler::CreateObjectRef+0x74
`0f59c130 000007fe`f58843f4 mscorwks!COMInterfaceMarshaler::WrapWithComObject+0x3a
`0f59c1a0 000007fe`f0268995 mscorwks!MarshalNative::WrapIUnknownWithComObject+0x134
`0f59c3c0 000007fe`f0270933 System_EnterpriseServices_ni!System.EnterpriseServices.RemoteServicedComponentProxy..ctor(System.Type, IntPtr, Boolean)+0xd5
`0f59c420 000007fe`f0270213 System_EnterpriseServices_ni!System.EnterpriseServices.FastRSCPObjRef.GetRealObject(System.Runtime.Serialization.StreamingContext)+0x33
`0f59c470 000007fe`f37254db System_EnterpriseServices_ni!System.EnterpriseServices.ServicedComponentProxyAttribute.CreateProxy(System.Runtime.Remoting.ObjRef, System.Type, System.Object, System.Runtime.Remoting.Contexts.Context)+0x133
`0f59c500 000007fe`f37253ff mscorlib_ni!System.Runtime.Remoting.RemotingServices.SetOrCreateProxy(System.Runtime.Remoting.Identity, System.Type, System.Object)+0x9b
`0f59c560 000007fe`f372466f mscorlib_ni!System.Runtime.Remoting.RemotingServices.GetOrCreateProxy(System.Runtime.Remoting.Identity, System.Object, Boolean)+0xbf
`0f59c5c0 000007fe`f027050a mscorlib_ni!System.Runtime.Remoting.RemotingServices.InternalUnmarshal(System.Runtime.Remoting.ObjRef, System.Object, Boolean)+0x12f
`0f59c650 000007fe`f40e3edf System_EnterpriseServices_ni!System.EnterpriseServices.ServicedComponentProxyAttribute.CreateInstance(System.Type)+0x2ba
`0f59c7c0 000007fe`f5416e61 mscorlib_ni!System.Runtime.Remoting.Activation.ActivationServices.IsCurrentContextOK(System.Type, System.Object[], Boolean)+0x9ba81f

对应的.NET 托管 Call Stack:

Child-SP         RetAddr          Call Site

000000000f59c3c0 000007fef0270933 System.EnterpriseServices.RemoteServicedComponentProxy..ctor(System.Type, IntPtr, Boolean)
000000000f59c420 000007fef0270213 System.EnterpriseServices.FastRSCPObjRef.GetRealObject(System.Runtime.Serialization.StreamingContext)
000000000f59c470 000007fef37254db System.EnterpriseServices.ServicedComponentProxyAttribute.CreateProxy(System.Runtime.Remoting.ObjRef, System.Type, System.Object, System.Runtime.Remoting.Contexts.Context)
000000000f59c500 000007fef37253ff System.Runtime.Remoting.RemotingServices.SetOrCreateProxy(System.Runtime.Remoting.Identity, System.Type, System.Object)
000000000f59c560 000007fef372466f System.Runtime.Remoting.RemotingServices.GetOrCreateProxy(System.Runtime.Remoting.Identity, System.Object, Boolean)
000000000f59c5c0 000007fef027050a System.Runtime.Remoting.RemotingServices.InternalUnmarshal(System.Runtime.Remoting.ObjRef, System.Object, Boolean)
000000000f59c650 000007fef40e3edf

System.EnterpriseServices.ServicedComponentProxyAttribute.CreateInstance

(System.Type)

通过上面的调用栈信息,可以得知当serviced componnet被创建的时候,.NET RCW 逻辑会在mscorwks!RCW::CreateRCW  里调用GC.AddMemoryPressure 对可能的额外内存需要做提前预估. 当内存在不停扩展时, AddMemoryPressure会增加 Induced GC 的计数(如我们在性能监视器里发现的), 并且调用GarbageCollect。

为了解决这种问题,我们需要在应用程序里减少创建Serviced Component的次数。光在COM+里面修改成Object Pooling是不够的,因为这种Induced GC是在每次应用程序调用RCW的时候都会发生。通过研究代码和测试,如在每次调用创建Serviced Component之前使用 RemoveMemoryPressure(4004) 用来抵消RCW里的相同bytes的AddMemoryPressure(4004)可以临时解决这个问题.

最终解决方法是我们在应用程序本身创建了自己的对象池(建立一组全局对象,简单管理它们的存在周期),以彻底减少CreateInsance和CreateRCW的调用。这样处理以后,即使在大压力情况下, 程序运行也是良好的。

调用.NET Serviced Component引发的性能问题及其解决的更多相关文章

  1. Mysql中where条件一个单引号引发的性能损耗

    日常写SQL中可能会有一些小细节忽略了导致整个sql的性能下降了好几倍甚至几十倍,几百倍.以下这个示例就是mysql语句中的一个单引号('')引发的性能耗损,我相信很多朋友都遇到过,甚至还在这样写. ...

  2. 记一次Task抛异常,调用线程处理而引发的一些随想

    记一次Task抛异常,调用线程处理而引发的一些随想 多线程调用,任务线程抛出异常如何在另一个线程(调用线程)中捕获并进行处理的问题. 1.任务线程在任务线程执行语句上抛出异常. 例如: private ...

  3. Redis核心知识之—— 时延问题分析及应对、性能问题和解决方法【★★★★★】

    参考网址: Redis时延问题分析及应对:http://www.cnblogs.com/me115/p/5032177.html Redis常见的性能问题和解决方法:http://www.search ...

  4. 探讨:crond 引发大量sendmail进程的解决办法

    某服务器账号comm无法登录,说是资源消耗完毕.于是用另一个账号登陆到服务器,检查common账号到底启动了哪些dd引起资源耗尽:ps -u common发现有个 sendmail的启动特别多例如:c ...

  5. ArcGIS API for Silverlight 调用WebService出现跨域访问报错的解决方法

    原文:ArcGIS API for Silverlight 调用WebService出现跨域访问报错的解决方法 群里好几个朋友都提到过这样的问题,说他们在Silverlight中调用了WebServi ...

  6. java 调用bash shell脚本阻塞的小问题的解决

    java  调用bash shell脚本阻塞的小问题的解决 背景 使用java实现的web端,web端相应用户的界面操作,使用java调用bash实现的shell脚本进行实际的操作,操作完成返回执行结 ...

  7. SpringBoot 内部方法调用,事务不起作用的原因及解决办法

    在做业务开发时,遇到了一个事务不起作用的问题.大概流程是这样的,方法内部的定时任务调用了一个带事务的方法,失败后事务没有回滚.查阅资料后,问题得到解决,记录下来分享给大家. 场景 我在这里模拟一个场景 ...

  8. 浅谈,seata在使用feign-url通过域名调用时分布式事务不生效的问题及解决

    浅谈,seata在使用feign-url通过域名调用时分布式事务不生效的问题及解决 ​ 在前几个月时,我们项目出现了分布式事务的问题,那么什么是分布式事务问题呢,简单的说,我们有俩服务A和B,它们对应 ...

  9. try catch引发的性能优化深度思考

    关键代码拆解成如下图所示(无关部分已省略): 起初我认为可能是这个 getRowDataItemNumberFormat 函数里面某些方法执行太慢,从 formatData.replace 到 une ...

随机推荐

  1. Linux下清除DNS缓存

    通常有的时候我们通过域名打不开网页,有可能使DNS缓存的原因(DNS解析的ip地址变了),解决办法如下: 方法一:$nslookup ecafe.pub(这里是你要打开的域名) 方法二:$sudo / ...

  2. -- > define的用法与学习(1)

    在不久之前,我一直不理解为神马大家在做题时经常用define来代替某些函数,或者用来直接定义某些极大的变量.It is not until today that I understand why it ...

  3. Ubuntu下常规方法安装软件

    一.通过apt-get 搜索: #搜索 apt-cache searche 7zip 安装: #安装 sudo apt-get install 7zip 更新: #查看特定软件的版本,前提是要安装ap ...

  4. leetCode(49):Count Primes

    Description: Count the number of prime numbers less than a non-negative number, n. 推断一个数是否是质数主要有下面几种 ...

  5. 3736 【HR】万花丛中2

    3736 [HR]万花丛中2  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description HR神犇在成功攻略ZX后,花心 ...

  6. Android分包MultiDex原理详解

    MultiDex的产生背景 当Android系统安装一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt.DexOpt的执行过程是在第一次加载Dex文件的时候执行的 ...

  7. 使用EL表达式正确情况下报错:javax.servlet.jsp cannot be resolved to a type

    这个错误可能是服务器自带的servlet库未导入的原因.右键项目属性,转到Targeted Runtimes,选择一个服务器,例如Tomcat,单击应用,可能就可以解决.

  8. la3211

    2-sat+二分... 每次二分答案然后连边2-sat...边要开到n*n 样例水得跟没有一样... #include<bits/stdc++.h> using namespace std ...

  9. DStream 转换操作------有状态转换操作

    import org.apache.spark.SparkConf import org.apache.spark.streaming.{Seconds, StreamingContext} obje ...

  10. iOS通讯录(纯纯的干货)

    一.iOS8.0 1.访问用户通讯录的两个框架 (1)AddressBookUI.framework 提供了联系人列表界面.联系人详情界面.添加联系人界面等,一般用于选择联系人 (2)AddressB ...