我希望你们中的一个能帮助我诊断网络服务电话的堆栈跟踪。我正在试图弄清楚什么导致我们的Web服务上的高CPU使用率,所以当CPU的峰值高于80%时,我已经进行了一些内存转储。 在运行转储文件(并选择简单的修复程序)后,我留下了一个特别有趣的文件。
bcryptPrimitives!accumulate+54
bcryptPrimitives!create_modulus+200
bcryptPrimitives!create_modulus_select_arithmetic+2d
bcryptPrimitives!rsa_import+254
bcryptPrimitives!MSCryptImportKeyPair+132
bcrypt!BCryptImportKeyPair+179
rsaenh!LocalPopulateBCryptPublicKey+206
rsaenh!CPImportKey+346
cryptsp!CryptImportKey+163
clr!StrongNameTokenFromPublicKey+1a5
clr!CAssemblyName::SetProperty+218
clr!BaseAssemblySpec::CreateFusionName+32b
clr!BaseAssemblySpec::GetFileOrDisplayName+4e
clr!AssemblyNameNative::ToString+164
[[HelperMethodFrame_1OBJ] (System.Reflection.AssemblyName.nToString)] System.Reflection.AssemblyName.nToString()
mscorlib_ni!System.Reflection.AssemblyName.get_FullName()+9
RazorEngine.Compilation.CompilerServiceBase.CurrentDomain_AssemblyResolve(System.Object, System.ResolveEventArgs)+124
mscorlib_ni!System.AppDomain.OnAssemblyResolveEvent(System.Reflection.RuntimeAssembly, System.String)+a4
clr!CallDescrWorkerInternal+83
clr!CallDescrWorkerWithHandler+4a
clr!MethodDescCallSite::CallTargetWorker+251
clr!AppDomain::RaiseAssemblyResolveEvent+d6860
[[GCFrame]]
clr!AppDomain::TryResolveAssembly+82
clr!AppDomain::PostBindResolveAssembly+d1
clr!`AppDomain::BindAssemblySpec'::`1'::catch$5+d7
MSVCR120_CLR0400!CallSettingFrame+20
MSVCR120_CLR0400!_CxxCallCatchBlock+f5
ntdll!RcConsolidateFrames+3
clr!AppDomain::BindAssemblySpec+ef7
clr!AssemblySpec::LoadDomainAssembly+1ec
clr!AssemblySpec::LoadAssembly+1b
clr!AssemblyNative::Load+304
[[HelperMethodFrame_PROTECTOBJ] (System.Reflection.RuntimeAssembly._nLoad)] System.Reflection.RuntimeAssembly._nLoad(System.Reflection.AssemblyName, System.String, System.Security.Policy.Evidence, System.Reflection.RuntimeAssembly, System.Threading.StackCrawlMarkByRef, IntPtr, Boolean, Boolean, Boolean)
mscorlib_ni!System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(System.Reflection.AssemblyName, System.Security.Policy.Evidence, System.Reflection.RuntimeAssembly, System.Threading.StackCrawlMark ByRef, IntPtr, Boolean, Boolean, Boolean)+d2
mscorlib_ni!System.Reflection.Assembly.Load(System.Reflection.AssemblyName)+3b
System_Xml_ni!System.Xml.Serialization.TempAssembly.LoadGeneratedAssembly(System.Type, System.String, System.Xml.Serialization.XmlSerializerImplementation ByRef)+1a6
System_Xml_ni!System.Xml.Serialization.XmlSerializer.FromMappings(System.Xml.Serialization.XmlMapping[], System.Type)+59
System_ServiceModel_ni!System.ServiceModel.Description.XmlSerializerOperationBehavior+Reflector+SerializerGenerationContext.GenerateSerializers()+dd
System_ServiceModel_ni!System.ServiceModel.Description.XmlSerializerOperationBehavior+Reflector+SerializerGenerationContext.GetSerializer(Int32)+74
System_ServiceModel_ni!System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.AddHeadersToMessage(System.ServiceModel.Channels.Message, System.ServiceModel.Description.MessageDescription, System.Object[], Boolean)+be
System_ServiceModel_ni!System.ServiceModel.Dispatcher.OperationFormatter.SerializeRequest(System.ServiceModel.Channels.MessageVersion, System.Object[])+e2
System_ServiceModel_ni!System.ServiceModel.Dispatcher.ProxyOperationRuntime.BeforeRequest(System.ServiceModel.Dispatcher.ProxyRpc ByRef)+1d1
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannel.PrepareCall(System.ServiceModel.Dispatcher.ProxyOperationRuntime, Boolean, System.ServiceModel.Dispatcher.ProxyRpc ByRef)+85
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannel.Call(System.String, Boolean, System.ServiceModel.Dispatcher.ProxyOperationRuntime, System.Object[], System.Object[], System.TimeSpan)+27f
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage, System.ServiceModel.Dispatcher.ProxyOperationRuntime)+6c
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)+133
mscorlib_ni!System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32)+1f4
clr!CTPMethodTable__CallTargetHelper3+12
clr!CallTargetWorker2+74
clr!CTPMethodTable::OnCall+1fb
clr!TransparentProxyStub_CrossContextPatchLabel+a
[[TPMethodFrame] (x.Server.WebReferences.x.x.Save)] x.Server.WebReferences.xxx.xxxServiceSoap.Save()
我们的架构很简单:我们有一个桌面客户端,它通过WCF与我们的服务进行通信。然后,我们的一些服务调用将通过Web服务将数据推送到另一个系统。上面的堆栈跟踪代表了这样的调用 - 从我们的服务到另一个服务。
我在加载XmlSerializer时收到第一次机会异常(从我的研究完成,这是预期的行为,如果找不到生成的程序集,它将生成一个并继续)。但是,对于每个进行的Web服务调用,我们似乎都会收到此异常。我的印象是,一旦生成了程序集,它将不再抛出第一次机会异常?)
这是Web服务调用的正常行为吗? 对我来说,好像我们每次都在生成这个程序集 - 然后轮流引发AssemblyResolveEvent - 然后执行RazorEngine.Compilation解析事件......这在此时完全没必要..
有什么想法和想法吗?
提前致谢
答案 0 :(得分:0)
从您的回溯中可以看出,一直占用的方法不是生成和加载动态创建的XmlSerializer
DLL的方法。相反,花费时间的方法是尝试加载pre-generated XmlSerializer
DLLs的方法。
要查看此内容,请查看reference source中的XmlSerializer.FromMappings
:
public static XmlSerializer[] FromMappings(XmlMapping[] mappings, Type type) {
if (mappings == null || mappings.Length == 0) return new XmlSerializer[0];
XmlSerializerImplementation contract = null;
Assembly assembly = type == null ? null : TempAssembly.LoadGeneratedAssembly(type, null, out contract);
TempAssembly tempAssembly = null;
if (assembly == null) {
if (XmlMapping.IsShallow(mappings)) {
return new XmlSerializer[0];
}
else {
if (type == null) {
tempAssembly = new TempAssembly(mappings, new Type[] { type }, null, null, null);
XmlSerializer[] serializers = new XmlSerializer[mappings.Length];
contract = tempAssembly.Contract;
for (int i = 0; i < serializers.Length; i++) {
serializers[i] = (XmlSerializer)contract.TypedSerializers[mappings[i].Key];
serializers[i].SetTempAssembly(tempAssembly, mappings[i]);
}
return serializers;
}
else {
// Use XmlSerializer cache when the type is not null.
return GetSerializersFromCache(mappings, type);
}
}
}
else {
XmlSerializer[] serializers = new XmlSerializer[mappings.Length];
for (int i = 0; i < serializers.Length; i++)
serializers[i] = (XmlSerializer)contract.TypedSerializers[mappings[i].Key];
return serializers;
}
}
调用TempAssembly.LoadGeneratedAssembly
:
/// <devdoc>
/// <para>
/// Attempts to load pre-generated serialization assembly.
/// </para>
/// </devdoc>
internal static Assembly LoadGeneratedAssembly(Type type, string defaultNamespace, out XmlSerializerImplementation contract)
运行时XmlSerializer
DLL的加载发生在GetSerializersFromCache
内,顾名思义,它被缓存。
如果XmlSerializer.FromMappings
在此特定回溯中的每次调用上花费了大量的CPU时间,那么您的服务器上可能还有一些过时的pre-compiled .XmlSerializers.dll
文件(在磁盘上或GAC中)需要清理吗?在每次调用时.Net可能会尝试加载它们,然后发现版本号或签名不匹配,然后抛出异常,这样做会消耗大量的CPU时间。或者,如果DLL没有过时,可能还有architecture mismatch?