2009-02-26 46 views
10

是否有人遇到过高内存分配负载下的应用程序每100秒执行一次第二代回收的情况?每100秒垃圾回收

我们使用具有8-16 GB物理内存的64位服务器。

应用程序有几GB数据存储在缓存中,无法清除,因为它实际上是由应用程序使用的。另外它在处理过程中收到很多分配GEN 0对象的请求。

对我来说,奇怪的是GEN 2收集器像钟表一样进行100秒的事实。我认为它不太可预测

+3

如果您需要对GC进行如此多的控制,那么您可能不应该使用像C#或VB.net这样的托管语言。 不,你不会做一个更好的GC,那么已经在.net中。许多人尝试过。所有都失败了。 = P – Tony 2009-06-03 14:23:02

+0

编写自己的垃圾回收器时,可以根据自己的确切需求自由定制垃圾回收器。这通常是一个比.NET框架开发人员面临的问题要简单得多的问题:为所有需求编写一个收集器。除了这一点之外,我普遍同意托尼的观点。 – 2009-06-05 04:00:31

回答

25

如果你在高内存负载下,并使用大量的对象,那么是的:GC会变得很忙......如果它打到第二代,那听起来像是你有很多的中/长寿命物体挂在...

我假设内存使用情况相当稳定?上面的可能是表示某种类型的伪泄漏(可能通过静态事件持有过多的对象等),也可能意味着您的内存使用率很高!

您使用多少内存?你可以考虑x64和一吨内存?或者,3gb交换机(x86)会多买几个字节?

+0

但是为什么“每隔100秒进行第二次收集”什么使得GC的时间安排如此可预测? – 2009-06-04 09:29:20

+1

可能是您使用内存方式的巧合 - 即每次需要100s才能获得关键性能,执行GC并发布相似的数量(如果您长时间进行类似处理,这种情况很常见)。或者它可以内置到GC中。我不认为我们会知道...... – 2009-06-04 09:44:39

+2

服务器GC模式没有任何基于时间的启发式方法,它会动态调整以反映您的分配率和生存对象。 – mfawzymkh 2009-06-05 17:19:58

1

我认为这是为.net。

当GC想要基于它的算法进行收集时收集。您可以建议垃圾收集器收集,但实际上可能不会做任何事情。

您可以使用GC.Collect()让GC查看是否可以收集垃圾。但是它可能不会从内存中删除项目。

另外,请确保您正确清除引用。含义unhooking事件,清除对象之间的引用。这将有助于GC收集不再在范围内的对象。

4

要发生这种情况,内存使用对于进程和系统都应该非常一致。垃圾收集是由这些事件触发:

  • 代0的预算是完全
  • GC.Collect的()被调用
  • CLR要释放内存
  • 的AppDomain关机
  • CLR关机

在你的情况下可能的候选人可能是定期收集(即由于分配)或定时收集()。

编辑:只是为了澄清分配。常规对象的分配总是在第0代中发生(例外是85000字节或更大的大对象,它们分配在大对象堆上)。实例仅移至第1代和第2代,当它们在集合中存活时。第1代和第2代没有直接分配。

此外,当第0/1代集合没有释放足够的内存(或明确请求完全收集时)时,会执行第2代集合(也称为全集合)。

8

如果您正在运行双核CPU,请尝试在app/web.config中设置GCServer =“true”。

就我而言,它占据了原始GC的10%左右,应用程序感觉更加快速。

4

您可能会生成更多的对象,然后可以一次适合年轻的堆,或者您有内存泄漏。

如果您正在密集地创建大量需要同时处于活动状态的对象,那么您可能会溢出年轻部分,并且一些对象必须复制到老一代。这会在更旧的堆填满时更频繁地强制完整收集。在这种情况下,您可能需要找到一种方法来分配更少的对象,除非有办法像Sun JVM那样请求更大的年轻堆。

如果你实际存储了某个地方的物体(比如在一个旧物体拥有的列表中),那么你就有一个逻辑泄漏。一般来说,你不希望旧对象指的是年轻的对象。这往往会让年轻的对象得到提升,并且GC算法通常会针对未发生的情况进行优化。另外,如果这可以显着缩短对象可以存活的范围(尽管它通常是多余的),您可能需要考虑清除引用。

除了这个,你只是有非常高的内存使用率,可能没有很多,你可以做。请记住,对于任何长时间运行的程序,您最终都必须执行一些GCing操作,并且一次需要的内存越多,出现的次数越多。

2

我假设你也使用.NET。我不确定你使用的是什么工具,但我是红门蚂蚁探测器的粉丝。我在工作中使用它。它可以识别哪些对象是占用资源。一旦你缩小了范围,希望你能找到有问题的代码并正确地释放资源。

检查您的代码,并确保尽可能调用Dispose()。

让我们知道它是如何发展的。

5

像发条一样发生的第二代集合表明GC.Collect方法被称为像钟表一样,或者分配就像发条一样。

您希望在垃圾回收中看到的随机性不可能发生,除非分配或GC.Collect调用真正是随机的。

鉴于您的服务器应用程序负载过重,并且在处理过程中创建新对象,我会认真考虑重构代码以查看是否可以在处理期间通过使用对象池来新创建更少的对象。

对象池与大多数垃圾收集器的不同之处在于,池中的对象一放回池中就可以重用,并且垃圾收集器需要在保存对象的前一块内存之前执行集合可以再次用作不同的对象。

1

由于您在服务器上运行,因此我假设它也是多核计算机。如果是这种情况,那么默认情况下你会得到Server GC的味道,所以你不需要在你的配置文件中设置任何东西。

您每隔100秒获得Gen2集合的事实是分配模式和对象生命周期模式的一个因素。 如果你的分配模式是一致的,你会得到一致的GC的,你可以通过在性能监视器下.NET CLR内存找PERF的柜台验证此行为

您需要跟踪以下度量

  1. GEN0类别

  2. 创1个类别

  3. Gen 2个的类别

  4. 每秒分配的字节数
  5. 所有堆中的字节数。

您应该看到最后一个度量像拼图一样移动,增加,Gen2 Collection开始,再次减少,循环重复。

为了避免这种情况,您需要检查

  • 可以,你可以要求之间的物体,在池?这将避免GC一起。
  • 如果不是,您是否可以减少每个请求分配的对象数量?

希望这会有所帮助。 谢谢

0

我不明白是什么导致“每秒钟执行第二代集合”,很难看到一个真正的生命系统对这样的“时钟工作”周期做任何事情。

如果你在高内存负载下,并使用了很多对象,那么是的:GC会变得很忙......如果它打到了gen-2,那么它听起来像你有很多mid /长寿命的物体徘徊在......你可能会产生更多的物体,然后一次能适应年轻的堆,或者你有内存泄漏。

假设你没有泄漏,你检查了memory profiler?我还假设你没有创建大量不必要的垃圾(例如,循环内部的string1 + = string2)。

我能想到可能帮助的两件事情。

通过限制Asp.net进程的请求数量(线程数),您可以限制活动对象的数量,并且加快单个请求的处理速度,因此不会让对象保持活动状态。 (你是否得到了很多线程接触开关?)

如果您要将对象存储在Asp.net缓存和/或Asp.net会话中。您可以尝试为此缓存信息使用进程外存储区,例如Asp.net会话服务器,第三方会话服务器,memcache或最近从Microsoft发布的缓存服务器(Velocity)。只需要在数据库中重新读取数据时,可能会更好,然后将其存储在长寿命的对象中。

失败以上,你使用了多少内存?你可以考虑x64和一吨内存?或一个webfarm ..

0

垃圾回收器经常被调用本身并不是一个巨大的问题 - 它可能是一个标志,你不是最佳地处理你的记忆(例如不通过引用传递大量的字符串进入方法)。

垃圾收集应该是非确定性的。值得注意的是,如果您正在运行一些关键任务,但是您的线程正在某个时刻睡眠(比如每隔100秒),那么垃圾收集器可能会借此机会在此时进行收集是合理的。更有可能的是,由于分配导致的消耗以或多或少规律的间隔达到峰值,并且垃圾收集器被调用来检索未使用的内存。

我强烈建议分析您的应用程序的内存消耗。

0

难道只是您的应用程序每隔100秒就会创建一个巨大的对象,所以GC不得不开始工作?

0

我也看过这个100秒的频率,它不会发生在所有的生产设置,但我已经看到它在本地和其他设置。