垃圾收集每100秒

时间:2009-02-26 13:50:33

标签: .net garbage-collection

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

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

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

对我而言,奇怪的是,GEN 2系列的表现就像时钟一样100秒。我认为它不太可预测

12 个答案:

答案 0 :(得分:25)

如果你的内存负载很高,并且使用了大量的对象,那么是的:GC会忙碌...如果它正在击中gen-2,那么听起来你有一个很多< / em>中间/长寿物体徘徊......

我假设内存使用率相当稳定?上面的可以表示某种伪泄漏(可能通过静态事件等持有太多对象),或者只是意味着你的内存使用率很高!

你使用了多少内存?你能考虑x64和大量的内存吗?或者,3gb交换机(x86)会为你多买几个字节吗?

答案 1 :(得分:8)

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

在我的情况下,它占原始GC的10%左右,应用程序感觉更加快捷。

答案 2 :(得分:5)

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

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

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

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

答案 3 :(得分:4)

为了实现这一点,内存使用对于进程和系统也应该非常一致。垃圾收集由以下任一事件触发:

  • 第0代的预算已满
  • GC.Collect()被称为
  • CLR希望释放内存
  • AppDomain关闭
  • CLR关闭

您案件中可能的候选人可能是定期收集(即由于分配)或定时收集()。

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

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

答案 4 :(得分:4)

您可能正在生成更多对象,然后可以同时放入年轻堆中,或者您有内存泄漏。

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

如果您实际存储某个对象(例如在旧对象拥有的列表中),那么您就会出现逻辑泄漏。通常,您不希望旧对象引用年轻对象。这往往会促进年轻对象的推广,并且GC算法通常会针对它没有发生进行优化。此外,您可能需要考虑清除引用,如果这会显着缩短对象可以存活的范围(尽管它通常是多余的)。

除非你只是拥有异常高的内存使用量,否则你可能无法做很多事情。请记住,对于任何长时间运行的程序,您最终都必须进行一些GCing,并且您一次需要的内存越多,它就越频繁。

答案 5 :(得分:2)

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

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

让我们知道它是怎么回事。

答案 6 :(得分:2)

由于您在服务器上运行,我认为它也是一台多核计算机。如果是这种情况,那么默认情况下会获得Server GC风格,因此您无需在配置文件中设置任何内容。

每100秒获得Gen2集合的事实是您的分配模式和对象生命周期模式的一个因素。 如果您的分配模式是一致的,您将获得一致的GC,您可以通过查看perfmon下的.Net CLR内存性能计数器来验证此行为

您需要跟踪以下指标

  1. Gen0系列

  2. 第1代收藏

  3. 第2代收藏

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

  6. 你应该看到最后一个指标像拼图一样移动,增加,Gen2收集开始,再次减少,循环重复。

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

    • 您可以在请求之间,在池中进行对象吗?这样可以避免GC一起使用。
    • 如果没有,您可以减少每个请求分配的对象数量吗?

    希望这会有所帮助。 感谢

答案 7 :(得分:1)

我认为这是针对.net。

GC会在想要基于其算法时收集。您可以建议收集垃圾收集器,但实际上可能没有做任何事情。

你可以使用GC.Collect()来询问GC是否可以收集垃圾。但是,它实际上可能无法从内存中删除项目。

注意:另外,请确保正确清除参考。意味着取消挂钩事件,清除对象之间的引用。这将有助于GC收集不再在范围内的对象。

答案 8 :(得分:0)

我不明白导致“每100秒执行第二代收集”的原因是什么,很少见到真正的生活系统对这种“时钟工作”周期做任何事情。

如果你的内存负载很高,并且使用了很多对象,那么是的:GC会很忙...如果它正在击中gen-2,那么听起来你有很多中/长 - 生活对象徘徊...你可能会生成更多的对象然后可以同时适应年轻的堆,或者你有内存泄漏。

假设您没有泄漏,请检查一下memory profiler吗?我也假设你没有创造很多不必要的垃圾(例如循环内的string1 + = string2)。

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

通过同时限制请求(线程)Asp.net进程的数量,您可以限制活动对象的数量,并加快单个请求的处理速度,因此不要让对象保持活动一段时间。 (你有很多线程接触开关吗?)

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

如果上述失败,您使用了多少内存?你能考虑x64和大量的内存吗?或者是一个网络农场..

答案 9 :(得分:0)

经常调用垃圾收集器本身并不一定是一个大问题 - 但它可能是一个标志,你没有很好地处理你的内存(例如没有通过引用传递大量字符串到方法)。

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

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

答案 10 :(得分:0)

可能只是你的应用程序每100秒创建一个巨大的对象,所以GC被迫使其工作?

答案 11 :(得分:0)

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