简体   繁体   English

C#WebAPI垃圾收集

[英]C# WebAPI Garbage Collection

I just delivered my first C# WebAPI application to the first customer. 我刚刚向第一个客户交付了我的第一个C#WebAPI应用程序。 Under normal load, performance initially is even better than I expected. 在正常负载下,性能最初比我预期的还要好。 Initially. 原来。

Everything worked fine until, at some point, memory was up and garbage collection started running riot (as in "It collects objects that are not yet garbage"). 一切工作正常,直到内存耗尽并且垃圾收集开始骚乱(如“它收集尚未垃圾的对象”中所述)。 At that point, there were multiple W3WP threads with some ten gigs of ram altogether, and single-digit gigs per worker. 那时,有多个W3WP线程,总共约有10个演出,每个工人个位数演出。 After a restart of the IIS everything was back to normal, but of course the memory usage is rising again. IIS重新启动后,一切恢复正常,但是内存使用率当然又在上升。

Please correct me if I am wrong, but 如果我错了,请纠正我,但是

  • Shouldn't C# have automatic garbage collection? C#不应该具有自动垃圾收集功能吗?
  • Shouldn't it be easy for GC to collect the garbage of a WebAPI application? GC收集WebAPI应用程序的垃圾不容易吗?

And please help me out: 并请帮助我:

  • How can I explicitly state what GC should collect, thus preventing memory leaks? 如何明确说明应该收集哪些GC,从而防止内存泄漏? Is someBigList = null; someBigList = null; the way to go? 要走的路?
  • How can I detect where the memory leaks are? 如何检测内存泄漏在哪里?

EDIT: Let me clarify some things. 编辑:让我澄清一些事情。

My .NET WebAPI application is mostly a bunch of 我的.NET WebAPI应用程序主要是

public class MyApiController:ApiController
{
    [HttpGet]
    public MyObjectClass[] MyApi(string someParam) {
        List<MyObjectClass> list = new List<MyObjectClass>();
        ...
        for/while/foreach {
            MyObjectClass obj = new MyObjectClass();
            obj.firstStringAttribute = xyz;
            ...
            list.Add(obj);
        }
        return list.ToArray();
    }
}

Under such conditions, GC should be easy: after "return", all local variables should be garbage. 在这种情况下,GC应该很简单:“返回”之后,所有局部变量都应该是垃圾。 Yet with every single call the used memory increases. 但是,每次调用都会增加使用的内存。

I initially thought that C# WebAPI programs behave similar to (pre-compiled) PHP: IIS calls the program, it is executed, returns the value and is then completely disposed off. 我最初以为C#WebAPI程序的行为类似于(预编译)PHP:IIS调用该程序,执行该程序,返回该值,然后将其完全清除。

But this is not the case. 但这种情况并非如此。 For instance, I found static variables to keep their data between runs, and now I disposed of all static variables. 例如,我发现静态变量可以在两次运行之间保留它们的数据,现在我处理了所有静态变量。

Because I found static variables to be a problem for GC: 因为我发现静态变量是GC的问题,所以:

 internal class Helper
 {
     private static List<string> someVar = new List<string>();
     internal Helper() {
         someVar=new List<string>();
     }
     internal void someFunc(string str) {
         someVar.Add(str);
     }
     internal string[] someOtherFunc(string str) {
         string[] s = someVar.ToArray();
         someVar=new List<string>();
         return s;
     }
 }

Here, under low-memory conditions, someVar threw a null pointer error, which in my opinion can only be caused by GC, since I did not find any code where someVar is actively nullified by me. 在这里,在内存不足的情况下,someVar引发了一个空指针错误,在我看来,这只能由GC引起,因为我没有找到任何代码将someVar主动使我无效。

I think the memory increase slowed down since I actively set the biggest array variables in the most often used Controllers to null, but this is only a gut feeling and not even nearly a complete solution. 我认为自从我将最常用的Controller中最大的数组变量主动设置为null以来,内存的增长速度变慢了,但这只是一种直觉,甚至不是一个完整的解决方案。

I will now do some profiling using the link you provided, and get back with some results. 现在,我将使用您提供的链接进行分析,并获得一些结果。

Shouldn't C# have automatic garbage collection? C#不应该具有自动垃圾收集功能吗?

C# is a programming language for the .NET runtime, and .NET brings the automatic garbage collection to the table. C#是.NET运行时的编程语言,.NET将自动垃圾收集带到表中。 So, yes, although technically C# isn't the piece that brings it. 因此,是的,尽管从技术上讲C#并不是带来它的部分。

Shouldn't it be easy for GC to collect the garbage of a WebAPI application? GC收集WebAPI应用程序的垃圾不容易吗?

Sure, it should be just as easy as for any other type of .NET application. 当然,它应该与任何其他类型的.NET应用程序一样简单。

The common theme here is garbage . 这里的共同主题是垃圾 How does .NET determine that something is garbage? .NET如何确定某些东西是垃圾? By verifying that there are no more live references to the object. 通过验证没有更多的对该对象的实时引用。 To be honest I think it is far more likely that you have verified one of your assumptions wrongly, compared to there being a serious bug in the garbage collector in such a way that "It collects objects that are not yet garbage". 坦白地说,与垃圾收集器中存在一个严重的错误(即“它收集尚未垃圾的对象”)相比,您错误地验证了一个假设的可能性更大。

To find leaks, you need to figure out what objects are currently held in memory, make a determination whether that is correct or not, and if not, figure out what is holding them there. 要查找泄漏,您需要确定内存中当前保留了哪些对象,确定该对象是否正确,如果不正确,则找出存在哪些对象。 A memory profiler application would help with that, there are numerous available, such as the Red-Gate ANTS Memory Profiler . 内存分析器应用程序将帮助您解决这一问题,它有很多可用的方法,例如Red-Gate ANTS内存分析器

For your other questions, how to make something eligible for garbage collection? 对于您的其他问题,如何使某些东西符合垃圾收集的条件? By turning it into garbage (see definition above). 通过将其变成垃圾(请参阅上面的定义)。 Note that setting a local variable to null may not necessarily help or be needed. 注意,将局部变量设置为null可能不一定有帮助或需要。 Setting a static variable to null , however, might . 但是, 可以将静态变量设置为null But the correct way to determine that is to use a profiler. 但是确定这一点的正确方法是使用探查器。

Here are some shot-in-the-dark type of tips you might look into: 这是您可能会发现的一些暗中技巧:

  • Look at static classes, static fields, and static properties. 查看静态类,静态字段和静态属性。 Are you storing data there that is accumulating? 您是否正在存储正在累积的数据?
  • How about static events? 静态事件如何? Do you have this? 你有这个吗? Do you remember to unsubscribe the event when you no longer need it? 您还记得不再需要该活动时取消订阅该活动吗?
  • And by "static fields, properties, and events", I also mean normal instance fields, properties and events that are held in objects that directly or indirectly are stored in static fields or properties. 所谓“静态字段,属性和事件”,也是指普通实例字段,属性和事件,这些实例保存在直接或间接存储在静态字段或属性中的对象中。 Basically, anything that will keep the objects in memory. 基本上,任何将对象保留在内存中的事物。
  • Are you remembering to Dispose of all your IDisposable objects? 您还记得要Dispose所有IDisposable对象吗? If not, then the memory being used could be unmanaged. 如果不是,则正在使用的内存可能无法管理。 Typically, however, when the garbage collector collects the managed object, the finalizer of that object should clean up the unmanaged memory as well, however you might allocate memory that the GC algorithm isn't aware of, and thus thinks it isn't a big problem to wait with collection. 但是,通常,当垃圾收集器收集托管对象时,该对象的终结器也应清除非托管内存,但是您可能会分配GC算法不知道的内存,因此认为它不是内存。等待收集的大问题。 See the GC.AddMemoryPressure method for more on this. 有关更多信息,请参见GC.AddMemoryPressure方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM