ConcurrentBag 中可能存在内存泄漏? [英] Possible memoryleak in ConcurrentBag?

查看:18
本文介绍了ConcurrentBag 中可能存在内存泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been reading into the new concurrent collections and esspecially the ConcurrentBag got my attention. Since the ConcurrentBag internally holds a local set on each individual thread using it to keep track of the items, this means that when the thread itself gets out of scope, it will still be referenced in memory by the ConcurrentBag. This in turn means both memory claimed by the thread, as well as native resources? (excuse me for not knowing the exact inner workings of the .NET thread object)

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

I can assume a usecase where you have 1 global ConcurrentBack for a multithreaded webservice where you have alot of clients adding tasks. These tasks are added by threads on the threadpool. Now the threadpool is a very efficient way to manage threads but it does remove and create Threads based on the amount of work. Therefore, such a webservice can at times find itself in trouble since the underlying bag is still referencing to many should be-destroyed threads.

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

I created a quick app to test this behavior:

    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

这种行为是否在意料之中?我在测试中犯了错误还是可以将其视为设计缺陷?

Is this behavior to be expected, did i make a mistake in my test or can this be considered a design flaw?

推荐答案

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

The ConcurrentBag does indeed keep things in thread local storage, and if you abandon threads it can cause a memory leak. However, the implementation is able to "steal" items from one thread's list to give to another thread. You can see this in action if you write the following:

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 键,您将看到该包确实已清空.

If you run that program and wait until the "Bag is empty" message before you hit Enter, you'll see that the bag is indeed emptied.

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

So, as long as there's one thread reading from the bag, it will be emptied eventually. Even if all the items were added by other threads.

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

So, yes, there's a possible memory leak. In practice, though, if multiple threads are accessing the bag, it's likely not a concern.

这篇关于ConcurrentBag 中可能存在内存泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆