我有一个最近从 .NET 3.5 迁移到 .NET 4.0 的 C# Windows 服务.没有进行其他代码更改.
I have a C# Windows Service that I recently moved from .NET 3.5 to .NET 4.0. No other code changes were made.
在 3.5 上运行时,给定工作负载的内存利用率大约为 1.5 GB 内存,吞吐量为每秒 20 X.(在这个问题的上下文中,X 无关紧要.)
When running on 3.5, memory utilzation for a given work load was roughly 1.5 GB of memory and throughput was 20 X per second. (The X doesn't matter in the context of this question.)
在 4.0 上运行的完全相同的服务使用 3GB 到 5GB+ 的内存,每秒速度不到 4 X.事实上,随着内存使用量继续攀升,服务通常会最终停止,直到我的系统处于 99% 的利用率并且页面文件交换变得疯狂.
The exact same service running on 4.0 uses between 3GB and 5GB+ of memory, and gets less than 4 X per second. In fact, the service will typically end up stalling out as memory usage continue to climb until my system is siting at 99% utilization and page file swapping goes nuts.
我不确定这是否与垃圾收集有关,或者与什么有关,但我无法弄清楚.我的窗口服务通过如下所示的配置文件开关使用服务器"GC:
I'm not sure if this has to do with garbage collection, or what, but I'm having trouble figuring it out. My window service uses the "Server" GC via the config file switch seen below:
<runtime>
<gcServer enabled="true"/>
</runtime>
将此选项更改为 false 似乎并没有什么不同.此外,根据我对 4.0 中新 GC 所做的阅读,大的变化只影响工作站 GC 模式,而不影响服务器 GC 模式.所以也许GC与这个问题无关.
Changing this option to false didn't seem to make a difference. Futhermore, from the reading I've done on the new GC in 4.0, the big changes only effect the workstation GC mode, not server GC mode. So perhaps GC has nothing to do with the issue.
想法?
嗯,这很有趣.
事实证明,根本原因是 SQL Server Reporting Services 的 LocalReport 类 (v2010) 在 .NET 4.0 上运行时的行为发生了变化.
The root cause turns out to be a change in the behavior of SQL Server Reporting Services' LocalReport class (v2010) when running this on top of .NET 4.0.
基本上,Microsoft 改变了 RDLC 处理的行为,以便每次处理报表时都在单独的应用程序域中完成.这实际上是为了解决由于无法从应用程序域卸载程序集而导致的内存泄漏.当 LocalReport 类处理一个 RDLC 文件时,它实际上会动态创建一个程序集并将其加载到应用程序域中.
Basically, Microsoft altered the behavior of RDLC processing so that each time a report was processed it was done so in a seperate application domain. This was actually done specifically to address a memory leak caused by the inability to unload assemblies from app domains. When the LocalReport class processed an RDLC file, it actually creates an assembly on the fly and loads it into the app domain.
在我的例子中,由于我正在处理大量的报告,这导致创建了大量的 System.Runtime.Remoting.ServerIdentity 对象.这是我对原因的提示,因为我对为什么处理 RLDC 需要远程处理感到困惑.
In my case, due to the large volume of report I was processing, this was resulting in very large numbers of System.Runtime.Remoting.ServerIdentity objects being created. This was my tip off to the cause, as I was confused as to why processing an RLDC required remoting.
当然,要调用另一个应用程序域中的类的方法,远程处理正是您使用的.在 .NET 3.5 中,这不是必需的,因为默认情况下,RDLC 程序集被加载到同一个应用程序域中.但是,在 .NET 4.0 中,默认情况下会创建一个新的应用程序域.
Of course, to call a method on a class in another app domain, remoting is exactly what you use. In .NET 3.5, this wasn't necessary as, by default, the RDLC-assembly was loaded into the same app domain. In .NET 4.0, however, a new app domain is created by default.
修复相当简单.首先,我需要使用以下配置启用旧版安全策略:
The fix was fairly easy. First I needed to go enable legacy security policy using the following config:
<runtime>
<NetFx40_LegacySecurityPolicy enabled="true"/>
</runtime>
接下来,我需要通过调用以下命令来强制在与我的服务相同的应用程序域中处理 RDLC:
Next, I needed to force the RDLCs to be processed in the same app domain as my service by calling the following:
myLocalReport.ExecuteReportInCurrentAppDomain(AppDomain.CurrentDomain.Evidence);
这解决了问题.
这篇关于.NET 4.0 中的内存使用率非常高的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!