gpt4 book ai didi

.net - ConcurrentBag 中可能存在内存泄漏?

转载 作者:行者123 更新时间:2023-12-04 07:44:22 24 4
gpt4 key购买 nike

我一直在阅读新的并发集合,特别是 ConcurrentBag 引起了我的注意。由于 ConcurrentBag 内部在每个单独的线程上持有一个本地集,使用它来跟踪项目,这意味着当线程本身超出范围时,它仍将在内存中被 ConcurrentBag 引用。这反过来意味着线程要求的内存以及 native 资源? (原谅我不知道 .NET 线程对象的确切内部工作原理)

我可以假设一个用例,其中您有 1 个全局 ConcurrentBack 用于多线程 Web 服务,其中您有很多客户端添加任务。这些任务由线程池上的线程添加。现在线程池是一种非常有效的线程管理方式,但它确实根据工作量删除和创建线程。因此,这样的 web 服务有时会发现自己遇到麻烦,因为底层包仍然引用许多应该被销毁的线程。

我创建了一个快速应用程序来测试这种行为:

    static ConcurrentBag<int> bag = new ConcurrentBag<int>();
static void FillBag() { for (int i = 0; i < 100; i++) { bag.Add(i); } }
static void PrintState() { Console.WriteLine("Bag size is: {0}", bag.Count); }
static void Main(string[] args)
{
var remote = new Thread(x =>
{
FillBag();
PrintState();
});
// empty bag
PrintState();
// first 100 items are added on main thread
FillBag();
PrintState();
// second 100 items are added on remote thread
remote.Start();
remote.Join();
// since the remote thread is gone out of scope, what happened to its local storage which is part of the bag?
PrintState();
// now force a cleanup
WeakReference weakRemoteReference = new WeakReference(remote);
remote = null;
GC.Collect();
GC.WaitForPendingFinalizers();
// Now check if the thread still exists
if (weakRemoteReference.IsAlive)
Console.WriteLine("Remote thread still exists");
PrintState();
Console.ReadLine();

输出证实了我的故事:
Bag size is: 0
Bag size is: 100
Bag size is: 200
Bag size is: 200
Remote thread still exists
Bag size is: 200

这种行为是否在意料之中,我是否在测试中犯了错误,或者这是否可以被视为设计缺陷?

最佳答案

ConcurrentBag确实将东西保存在线程本地存储中,如果你放弃线程,它可能会导致内存泄漏。但是,该实现能够从一个线程的列表中“窃取”项目以提供给另一个线程。如果您编写以下内容,您可以看到这一点:

ConcurrentBag<int> MyBag = new ConcurrentBag<int>();

void DoIt()
{
for (int i = 0; i < 10; ++i)
{
MyBag.Add(i);
}

ThreadPool.QueueUserWorkItem(EmptyBag);

Console.Write("Press Enter:");
Console.ReadLine();

Console.WriteLine("{0} items in bag", MyBag.Count);
}

void EmptyBag(object state)
{
int take;
while (MyBag.TryTake(out take))
{
Console.WriteLine(take);
}
Console.WriteLine("Bag is empty");
}

如果您运行该程序并等待“Bag is empty”消息,然后再按 Enter,您将看到该包确实已清空。

所以,只要有一个线程从包中读取,它最终就会被清空。即使所有项目都是由其他线程添加的。

所以,是的,可能存在内存泄漏。但在实践中,如果多个线程正在访问包,这可能不是问题。

关于.net - ConcurrentBag 中可能存在内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5353164/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com