C# 解释静态只读ConcurrentDictionary是否<;字符串,异步本地<;对象>&燃气轮机;状态泄漏内存?

C# 解释静态只读ConcurrentDictionary是否<;字符串,异步本地<;对象>&燃气轮机;状态泄漏内存?,c#,.net,memory-leaks,C#,.net,Memory Leaks,我有一个应用程序,似乎积累了很多内存。 一个嫌疑犯在下面,我只是想了解它到底在做什么。或者,更具体地说,它是如何清理的 private static readonly ConcurrentDictionary<string, AsyncLocal<object>> State; 垃圾收集器是一只奇怪的野兽,因此值得了解它的行为。(注意,这是对GC的一种过于简单的看法) 首先,如果一个对象只存在一个引用,那么该对象不会被视为垃圾,因此它永远不会被收集。 因为你的字典是静态

我有一个应用程序,似乎积累了很多内存。 一个嫌疑犯在下面,我只是想了解它到底在做什么。或者,更具体地说,它是如何清理的

private static readonly ConcurrentDictionary<string, AsyncLocal<object>> State;

垃圾收集器是一只奇怪的野兽,因此值得了解它的行为。(注意,这是对GC的一种过于简单的看法)

首先,如果一个对象只存在一个引用,那么该对象不会被视为垃圾,因此它永远不会被收集。 因为你的字典是静态的,它总是会存在的,所以它包含的任何东西都会引用它。如果没有对所包含对象的其他引用,并且您将其从字典中删除,那么它将变得不可访问,因此将被收集为垃圾。确保没有对对象的引用是确保收集对象的方法。很容易忘记你在某处做的一些引用,这些引用使对象保持活力

其次,垃圾收集器不会连续运行。它在内存资源不足并且需要释放一些内存时运行。这样就不会占用CPU而损害主要应用程序。这意味着在下次垃圾回收之前,对象仍可以在内存中保留一段时间。这会使内存使用率有时看起来很高,即使不是这样

第三,垃圾收集器有“代”。第0代对象是最新和最短命的对象。收集第0代对象的频率最高,但仅在需要内存时

第1代包含即将成为长寿命对象的短命对象。与第0代对象相比,收集它们的频率更低。事实上,只有当第0代集合没有释放足够的内存时,才会发生第1代集合

第2代对象的寿命很长。这些对象通常是在应用程序生命周期内存在的静态对象。类似地,当第1代集合没有释放足够的内存时,也会收集这些数据


最后是大型对象堆。消耗大量内存的对象需要时间移动(垃圾收集过程的一部分涉及在收集发生后对内存进行碎片整理),因此,除非收集没有释放足够的内存,否则它们往往保持未收集状态。有些人将其称为第3代,但在必要时,它们实际上会在第2代中收集。

我知道静态字典仍然存在,但值是否也存在,或者我是否需要手动删除?否,它们神奇地取消了。。。说真的,你们把一些东西放到字典里,所以字典会一直引用这个对象,若有对象引用,它就不能被GCed。。。你不明白什么。。。所以很明显,如果需要的话,你必须删除字典中的词条,或者你应该使用
WeakReference
好的,谢谢,但我同意,不必粗鲁。字典中的值是AsyncLocal位。我的理解是,当异步调用链发生时,字典中的值将特定于该调用。如果我有并发异步调用(就像在服务结构中发生的那样),它们中的每一个都将获得唯一的状态[“SomeFoo”]。看起来State将具有所有线程的键,但该值将特定于当前执行上下文?那么,这是否意味着我需要在任务完成之前删除AsyncLocal,否则它将被困在内存中?请分享您的代码以及
状态
字典的使用方法。这很有帮助,但我还没有完全理解特定代码的性质。我得到的静态数据将保留在内存中,但对于调用的每个服务,我的代码都将使用新值更新状态[“SomeHeader”]。但是,因为字典值是AsyncLocal,所以它只针对特定任务进行更新。我的服务将“永远”运行,词典也会持续这么长时间。这是否意味着每项任务完成后,都会在状态字典中留下一个残留物?看到困惑了吗?接受你的答案,菲尔,但我采取了一种稍微新的方法。我将把我的头视为一个堆栈,以便在传入调用时,我计划将一个项推送到当前值上,然后将该项弹出。不管怎样,让堆栈流通过调用都会有一些价值,并且当我不再使用当前帧时,它会清楚地表明这一点。FWIW,我编写了一个测试来使用AsyncLocal的ConcurrentDictionary,老实说,在异步调用完成后,仍然无法判断AsyncLocal本身的值是否消失。它不在字典里,但仍在内存中…@WillComeaux让我知道它是否确实减少了内存占用或在@PeterBons创建了一个公共关系。仍在测试是否真的存在问题。我看得越多,我就越相信有,但同时。。。在早些时候发现了这条推文,但作者没有详细说明他是否证实了这条推文。可能会回复,看看他是否挖得更深。同时,仍在努力使远程上下文按我希望的方式运行,而不是泄漏内存。:)我将在github上继续我在那里的想法。
        RemotingContext.FromRemotingMessageHeader(header);

        //Some other code where the actual service is invoked (and where RemotingContext values can be references for the current call.

        return null;
    }