Tag: 垃圾收集

服务器模式GC似乎永远不会收集Gen 0堆

澄清的问题(tl; dr) 在阅读和分析下面介绍的所有结果之后,问题似乎归结为GC在服务器模式下不为我们的应用程序收集Gen 0堆,一旦它改为工作站模式,问题就消失了。 原始问题和细节 我的问题有点涉及: 这个问题和这个问题 。 我们最近在我们的测试环境中遇到了.NET应用程序中的内存泄漏问题,工作进程在负载下或在无负载时会迅速升至450MB左右。 这个问题无法在我们的开发环境中复制,主要区别在于开发环境是物理服务器,而测试环境是由Puppet虚拟化和控制的(除此之外我对环境本身并不了解)。 为了有希望看到哪些对象负责占用所有内存,我在测试服务器上运行了Ants Memory Profiler,我发现所有内存都保留为未使用且永远不会被释放。 在研究可能导致这种情况的原因时,我遇到了这个论坛post ,这反过来又引导我阅读这篇文章 。 我最后尝试了它建议的配置,将GC置于工作站模式: 在运行iisreset并重新运行我的内存分析后,问题完全消失了,这很好,但仍然没有真正解释首先发生的事情。 我确实做了一些阅读并发现了这个问题 ,这使我相信这种配置变化最终可能会对我们的应用程序的吞吐量产生不利影响。 所以我的问题是:什么会导致IIS工作进程累积大量未被垃圾收集的未使用内存? 编辑:为了更清楚地澄清我的问题,我相信我们已经certificate代码不对此负责,因为完全相同的代码在开发环境中不会遇到此问题。 以下是我在配置更改之前和之后的内存分析截图,这里没有很多信息,但图表确实显示了内存趋势。 编辑2:这是我可以收集的服务器规格,我可能会得到更多只需要时间。 开发环境:物理机CPU:单核内存:6GB 测试环境:虚拟机CPU:4个逻辑线程(我无法评论CPU数量)内存:8GB Machine.Config文件的唯一区别是开发环境正在为端点和服务行为添加“Microsoft.VisualStudio.Diagnostics.ServiceModelSink.Behavior”。 并且测试环境当前具有aspnet.config文件中先前提到的GC设置。 编辑3:做了一些更多的分析并注意到我可以在Ants中添加更多的计数器,特别是我添加了“Gen 0堆大小”,看起来这是问题的根源。 当GC处于服务器模式时,当我触发测试时,我正在用于分析此行,立即跳转到~300MB然后再回到~230MB但是从不会一直回落(下图)。 在工作站模式下使用GC运行相同的分析会看到Gen 0堆大小具有小得多的初始峰值,并在请求完成时返回到基本为零(下图)。 对此进行更多搜索会引出另一个更相关的SO问题,但是他的发现是这个内存使用是一个非问题,而在我的情况下,服务实际上需要每天至少手动重启一次。 我还发现这篇文章在这个问题上有以下几点说明(这似乎描述了几乎完美的情况: 第0代可能在64位系统上拥有更多的对象,尤其是当您使用服务器垃圾收集而不是工作站垃圾收集时。 这是因为在这些环境中触发第0代垃圾收集的阈值更高,并且第0代集合可以变得更大。 当应用程序在触发垃圾回收之前分配更多内存时,性能会得到改善。 虽然问题仍然存在,在服务器模式下,第0代堆似乎从未收集过,而不是经常收集。

C#中的静态方法与实例方法

对于我正在编写的应用程序,我希望具有极端的可扩展性,并且扩展方法似乎可以提供我想要的内容,以及在没有实例的情况下调用它们的能力,我也需要它。 我记得读过静态方法比实例方法更快但没有得到GC的优点。 它是否正确? 我不太可能改变我的设计,除非我找到一个更好的替代设计而不是速度。 但仍然需要额外的信息,我想知道速度,GC等的差异。 编辑:谢谢。 更多信息:假设我们有一个Person类: class Person 它可以有一个实例Distance方法,如: this.Distance (Person p) 这很好,但这并没有让我能够计算2点之间的距离(比如Point3),而不会创建Person类的实例。 我想要做的是: class Person (no Distance methods) 但是距离的扩展方法: Distance (this Person, Person) Distance (this Point3, Point3) 这样我可以这样做: myPerson.Distance (yourPerson) 和 Extensions.Distance (pointA, pointB) EDIT2:@Jon,是的,我认为这就是所谓的(没有得到GC的优点),但我不知何故认为静态方法会产生这种负担/开销。

C#:收集WeakReference之前的通知?

在C#/ .NET中,有没有办法在弱引用指向的对象被破坏之前获得通知? 基本上,我想允许收集一个对象,但在对象被销毁之前做一些事情,而不修改代码来添加析构函数(因为我不知道究竟什么类型的对象将被我的代码起诉)。 谢谢,罗伯特

如何在Windows 7中模拟低内存条件

我有一个用C#编写的应用程序运行良好,但偶尔会在现场发出错误,我们认为这些错误是由于内存条件不足或与垃圾收集器的交互造成的。 如果有人有兴趣,这里描述: 无法将类型为’NHibernate.Impl.ExpandedQueryExpression’的对象强制转换为’NHibernate.Linq.NhLinqExpression’ 我想尝试重现这个以进行调试,但我的开发机器有太多的内存。 我删除了页面文件,因此我的虚拟内存仅限于12GB的物理内存,所以除了物理删除ram之外,是否有人对如何在开发环境中模拟低内存条件有任何建议? 编辑: 删除了询问监视垃圾收集器的工具?

我可以“启动”CLR GC以期望使用挥霍的内存吗?

我们有一个服务器应用程序,它可以进行大量的内存分配(包括短期内存和长期内存)。 我们在启动后不久就看到了大量的GC2系列,但这些系列在一段时间后会冷静下来(即使内存分配模式不变)。 这些系列在早期就达到了性能。 我猜这可能是由GC预算引起的(对于Gen2?)。 有没有什么方法可以设置这个预算(直接或间接),以使我的服务器在开始时表现更好? 我看到的一组反直觉的结果:我们大大减少了内存(和大对象堆)分配的数量,这使得长期性能得到改善,但早期性能变差,并且“安定下来” “时间变长了。 GC显然需要一段时间来实现我们的应用程序是一个记忆猪并相应地适应。 我已经知道这个事实,我如何说服GC? 编辑 操作系统:64位Windows Server 2008 R2 我们正在使用.Net 4.0 ServerGC Batch Latency。 尝试了4.5和3种不同的延迟模式,虽然平均性能略有提高,但最差情况下的性能实际上已经恶化 EDIT2 GC峰值可以将从可接受时间到不可接受时间的时间加倍(我们正在谈论秒数) 几乎所有的峰值都与第2代集合相关 我的测试运行导致最终的32GB堆大小。 最初的泡沫持续时间为运行时间的第1个1/5,之后的性能实际上更好(峰值频率更低),即使堆正在增长。 测试结束时的最后一个峰值(具有最大堆大小)与初始“训练”期间的峰值中的2个(即坏)相同(具有更小的堆)

了解局部变量的垃圾收集器行为

下面是一个非常简单的控制台应用程序(尝试小提琴 ): using System; using System.Threading; using System.Threading.Tasks; public class ConsoleApp { class Callback { public Callback() { } ~Callback() { Console.WriteLine(“~Callback”); } } static void Test(CancellationToken token) { Callback callback = new Callback(); while (true) { token.ThrowIfCancellationRequested(); // for the GC GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); GC.WaitForPendingFinalizers(); Thread.Sleep(100); } // no need for KeepAlive? // GC.KeepAlive(callback); } […]

Finalizer在其对象仍在使用时启动

总结: C#/ .NET应该是垃圾回收。 C#有一个析构函数,用于清理资源。 当一个对象A被垃圾收集在我试图克隆其变量成员之一的同一行时会发生什么? 显然,在多处理器上,垃圾收集器有时赢了…… 问题 今天,在关于C#的培训课程中,老师向我们展示了一些仅在多处理器上运行时才包含错误的代码。 我将总结一下,有时候,编译器或JIT通过在从被调用方法返回之前调用C#类对象的终结器来搞砸。 Visual C ++ 2005文档中给出的完整代码将作为“答案”发布,以避免提出非常大的问题,但必要的内容如下: 以下类具有“Hash”属性,该属性将返回内部数组的克隆副本。 在构造中,数组的第一项值为2.在析构函数中,其值设置为零。 关键是:如果你试图获得“示例”的“哈希”属性,你将得到一个干净的数组副本,其第一个项目仍然是2,因为正在使用该对象(因此,不是垃圾收集/定稿): public class Example { private int nValue; public int N { get { return nValue; } } // The Hash property is slower because it clones an array. When // KeepAlive is not used, the finalizer sometimes runs before […]

当对象完成但尚未收集垃圾时的弱参照行为

这是关于在C#/ .NET中进行对象最终化和集合的学术问题。 背景阅读是C#语言规范自动内存管理的第3.9节。 当没有对对象的显式引用时,它可能变为垃圾回收。 它变得“有资格进行破坏”。 在将来的某个时刻(例如,如果强制进行垃圾收集),将运行对象的析构函数。 在析构函数中,如果保存对该对象的引用,该对象将被最终确定,但不符合收集条件。 这可能导致对象处于已完成但尚未收集的状态。 规范的第3.9节就是一个例子。 此时,该对象仍然存在,因为它尚未被垃圾收集。 但是,引用该对象的WeakReference报告IsAlive值为false,表示该对象已被收集。 核心问题是 – IsAlive属性真正报道的是什么? 我们知道我们不能信任此属性的值true,因为在读取之后该值很快就会变为false。 但是false值是值得信赖的,并且意味着(根据文档)表明该对象已被垃圾收集。 那么在这种情况下IsAlive属性告诉我们什么呢? 不严格对象是否被垃圾收集,因为我们认为对象处于最终但未收集的状态。 这是一个显示行为的示例。 public class Dog { public static Dog KeepDogRef; public string Name { get; set; } public Dog(string name) { Name = name; } ~Dog() { Console.WriteLine(“Dog destructor for ” + Name + ” called”); Dog.KeepDogRef = […]

CLR垃圾收集方法是否意味着抛出循环对象引用是安全的?

我有一个理论认为CLR垃圾收集机制意味着我可以在对象层次结构中使用循环引用,而不会为拆卸和垃圾收集创建死锁。 这是一个安全的假设吗? (目标语言VB.NET)

.NET运行时如何移动内存?

众所周知,.NET垃圾收集器不只是“删除”堆上的对象,而且还使用内存压缩来对抗内存碎片。 根据我的理解,基本上将内存复制到一个新的地方,旧的地方在某些时候被删除。 我的问题是:这是如何工作的? 我最感兴趣的是GC在一个单独的线程中运行,这意味着我们正在处理的对象可以在我们执行代码时由GC移动。 问题的技术细节 为了说明,让我更详细地解释一下我的问题: class Program { private int foo; public static void Main(string[] args) { var tmp = new Program(); // make an object if (args.Length == 2) // depend the outcome on a runtime check { tmp.foo = 12; // set value *** } Console.WriteLine(tmp.foo); } } 在这个小例子中,我们创建一个对象并在对象上设置一个简单变量。 点’***’对问题来说很重要:如果’tmp’的地址移动,’foo’会引用不正确的东西,一切都会破坏。 垃圾收集器在单独的线程中运行。 所以据我所知,’tmp’可以在这个指令中移动,’foo’最终会得到不正确的值。 […]