In an enterprise user environment,. NET serviced component is widely used. It is better to put the traditional COM + encapsulation and. NET application logic, which plays an important role in server-side applications. The use of the. NET serviced Component needs to be noted in a number of ways, especially for the rational application of object resources (pooling) and timely release (Dispose). There are many specific discussions on this subject in the present article.
Here, I'm going to analyze the problem of a high CPU that was raised by a. NET serviced component in a specific case that was previously handled. More than one customer encountered such problems, feel the need to share with you.
If the program has a high CPU, the application thread must have a busy operation, such as repeated computations or long loops, rather than waiting for a database, lock, or other resource. If this program is. NET programs, frequent garbage collection lead to high CPU must be important to consider. Because each GC needs to check the. NET object Tree and adjust. Net heap, is a heavy operation. We can see the two performance counter metrics for the%time in GC and induced GC under the. NET CLR Memory Object by capturing the performance log (Perfmon) to determine if the high CPU is related to GC.
In this example, by looking at Performance Monitor, you can see that the induced GC is growing very fast, indicating the direct cause of this high CPU:
Typically, the induced GC appears as a direct call to Gc.collect within the client code. However, after reviewing the customer code, it was found that no gc.collect appeared at all.
We note that the. NET Enterprise serviced components are used in this program, and it is recommended that customers use the Dispose method to release these components instead of DisposeObject:
Http://msdn.microsoft.com/en-us/library/system.enterpriseservices.servicedcomponent.disposeobject.aspx
And try to enable the object pool, it is not obvious that the improvement is:
Http://www.codeproject.com/Articles/579/COM-Object-Pooling
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684273 (v=vs.85). aspx
So in this program high CPU time grabbed memory Dump.
Note: There are many ways to grab memory dump, you can use WinDbg, Procdump or Debugdiag
By carefully analyzing memory Dump, it is found that the induced GC logic appears in the following call stack:
Non- call Stack:
CHILD-SP retaddrPagerSite00000000`0f59bbe8 00000000' 7704ce00ntdll! Zwwaitforsingleobject+0xa00000000`0f59bbf0 000007fe' f52fa74a kernel32! waitforsingleobjectex+0x9c00000000`0f59bcb0 000007fe' f52fa83b mscorwks! clreventwaithelper+0x4200000000`0F59BD10 000007fe' F53cee38 mscorwks!clrevent:: waitex+0x6300000000`0f59bdc0 000007fe' F53c1cb7 mscorwks!SVR::Gc_heap:: wait_for_gc_done+0x8800000000`0f59be00 000007fe' F542913b mscorwks!SVR::Gcheap:: garbagecollectgeneration+0x14700000000`0f59be90 000007fe' F5412ac3 mscorwks!SVR::Gcheap:: garbagecollect+0x5b00000000`0f59bee0 000007fe' F57301a5 mscorwks!Gcinterface:: addmemorypressure+0x13b00000000`0f59bf70 000007fe' F57b9beb mscorwks!RCW:: addmemorypressure+0x1500000000`0f59bfb0 000007fe' F57dbbf4 mscorwks!RCW:: creatercw+0x17b00000000`0f59c030 000007fe' F57dbdea mscorwks!Cominterfacemarshaler:: createobjectref+0x7400000000`0f59c130 000007fe' F58843f4 mscorwks!Cominterfacemarshaler:: wrapwithcomobject+0x3a00000000`0f59c1a0 000007fe' f0268995 mscorwks!marshalnative:: wrapiunknownwithcomobject+0x13400000000`0f59c3c0 000007fe' f0270933 system_enterpriseservices_ni! System.EnterpriseServices.RemoteServicedComponentProxy. ctor (System.Type, IntPtr, Boolean) +0xd500000000`0f59c420 000007fe' f0270213 system_enterpriseservices_ni! System.EnterpriseServices.FastRSCPObjRef.GetRealObject (System.Runtime.Serialization.StreamingContext) +0x33 00000000`0f59c470 000007fe' f37254db system_enterpriseservices_ni! System.EnterpriseServices.ServicedComponentProxyAttribute.CreateProxy (System.Runtime.Remoting.ObjRef, System.Type, System.Object, System.Runtime.Remoting.Contexts.Context) +0x13300000000`0f59c500 000007fe' f37253ff mscorlib_ni! System.Runtime.Remoting.RemotingServices.SetOrCreateProxy (System.Runtime.Remoting.Identity, System.Type, System.Object) +0x9b00000000`0f59c560 000007fe' f372466f mscorlib_ni! System.Runtime.Remoting.RemotingServices.GetOrCreateProxy (System.Runtime.Remoting.Identity, System.Object, Boolean) +0XBF00000000`0f59c5c0 000007fe' f027050a mscorlib_ni! System.Runtime.Remoting.RemotingServices.InternalUnmarshal (System.Runtime.Remoting.ObjRef, System.Object, Boolean) +0x12f00000000`0f59c650 000007fe' F40e3edf system_enterpriseservices_ni! System.EnterpriseServices.ServicedComponentProxyAttribute.CreateInstance (System.Type) +0x2ba00000000`0f59c7c0 000007fe' F5416e61 mscorlib_ni! System.Runtime.Remoting.Activation.ActivationServices.IsCurrentContextOK (System.Type, system.object[], Boolean) + 0x9ba81f
The corresponding. NET managed call Stack:
CHILD-SP RetAddrPagerSite000000000f59c3c0 000007fef0270933System.EnterpriseServices.RemoteServicedComponentProxy. ctor (System.Type, IntPtr, Boolean)000000000f59c420 000007fef0270213System.EnterpriseServices.FastRSCPObjRef.GetRealObject (System.Runtime.Serialization.StreamingContext)000000000f59c470 000007fef37254dbSystem.EnterpriseServices.ServicedComponentProxyAttribute.CreateProxy (System.Runtime.Remoting.ObjRef, System.Type, System.Object, System.Runtime.Remoting.Contexts.Context)000000000f59c500 000007fef37253ffSystem.Runtime.Remoting.RemotingServices.SetOrCreateProxy (System.Runtime.Remoting.Identity, System.Type, System.Object)000000000f59c560 000007fef372466fSystem.Runtime.Remoting.RemotingServices.GetOrCreateProxy (System.Runtime.Remoting.Identity, System.Object, Boolean)000000000f59c5c0 000007fef027050aSystem.Runtime.Remoting.RemotingServices.InternalUnmarshal (System.Runtime.Remoting.ObjRef, System.Object, Boolean)000000000f59c650 000007FEF40E3EDFSystem.EnterpriseServices.ServicedComponentProxyAttribute.CreateInstance (System.Type)
With the above call stack information, you will know that when serviced componnet is created, the. NET RCW logic is in the mscorwks! RCW::CREATERCW calls Gc.addmemorypressure to make an advance estimate of the possible additional memory needs. When memory is expanding, addmemorypressure increases the count of induced GC (as we found in Performance Monitor) and calls Garbagecollect.
To solve this problem, we need to reduce the number of serviced component created in the application. It is not enough for the light to be modified into object pooling in COM + because this induced GC occurs every time the application invokes the RCW. By studying code and testing, such as using Removememorypressure (4004) to counteract the same bytes addmemorypressure (4004) in the RCW before each call to create serviced component Can solve this problem temporarily.
The final solution is that we create our own pool of objects in the application itself (creating a set of global objects that simply manage their existence cycles) to drastically reduce createinsance and CREATERCW calls. After this treatment, even under high pressure conditions, the program runs well.
Calling the. NET serviced component performance issues and their solutions