【问题标题】:C#: BackgroundWorker cloning resources?C#:BackgroundWorker 克隆资源?
【发布时间】:2010-03-22 14:11:16
【问题描述】:

问题

我已经在这个特殊的问题上苦苦挣扎了两天,只是没有想法了。一点...背景:我们有一个 WinForms 应用程序,它需要访问数据库,从该数据构造一个相关的内存对象列表,然后显示在 DataGridView 上。重要的一点是,我们首先填充应用程序范围的缓存(List),然后创建 DGV 所在表单的本地缓存镜像(使用 List 构造函数参数)。

因为获取数据需要几秒钟的时间(数据库位于 LAN 服务器上)才能加载,我们决定使用 BackgroundWorker,并且仅在加载数据后刷新 DGV。但是,似乎通过 BGW 进行加载会导致一些内存泄漏......或者我的错误。当使用阻塞方法调用加载时,应用程序消耗大约 30MB 的 RAM;使用 BGW,这将跃升至 80MB!虽然看起来可能没有那么多,但我们的客户对此并不满意。

相关代码

表格

private void MyForm_Load(object sender, EventArgs e)
{
    MyRepository.Instance.FinishedEvent += RefreshCache;
}
private void RefreshCache(object sender, EventArgs e)
{
    dgvProducts.DataSource = new List<MyDataObj>(MyRepository.Products);
}

存储库

private static List<MyDataObj> Products { get; set; }
public event EventHandler ProductsLoaded;

public void GetProductsSync()
{
    List<MyDataObj> p;

    using (MyL2SDb db = new MyL2SDb(MyConfig.ConnectionString))
    {
        p = db.PRODUCTS
        .Select(p => new MyDataObj {Id = p.ID, Description = p.DESCR})
        .ToList();
    }

    Products = p;

    // tell the form to refresh UI
    if (ProductsLoaded != null)
        ProductsLoaded(this, null);

}

public void GetProductsAsync()
{
    using (BackgroundWorker myWorker = new BackgroundWorker())
    {
        myWorker.DoWork += delegate
        {
            List<MyDataObj> p;
            using (MyL2SDb db = new MyL2SDb(MyConfig.ConnectionString))
            {
                p = db.PRODUCTS
                .Select(p => new MyDataObj {Id = p.ID, Description = p.DESCR})
                .ToList();
            }

            Products = p;
        };

        // tell the form to refresh UI when finished
        myWorker.RunWorkerCompleted += GetProductsCompleted;
        myWorker.RunWorkerAsync();
    }
}

private void GetProductsCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (ProductsLoaded != null)
        ProductsLoaded(this, null);
}

结束!

GetProductsSync 或 GetProductsAsync 在主线程上调用,上面没有显示。会不会是 GarbageCollector 只是因为两个线程而丢失了?还是任务管理器显示的值不对?

对任何回应、建议和批评都将不胜感激。

【问题讨论】:

  • 您正在处理仍在工作的 BackgroundWorker。你不应该在那里使用using 声明。
  • 是的,Slaks 是对的。在 Bgw 周围删除 using。
  • 您在什么时候分离 RunWorkerComplete 事件?
  • @SkippyFire: BackgroundWorkerDispose 方法实际上并没有做任何事情。 (只是继承自Component
  • @Henk 你在现场。不确定我是否应该评论或添加答案...在.Net Memory Profiler 下运行应用程序,然后出现一张有趣的图片 - 数字几乎相同!在同步和异步情况下,MyDataObj 实例的预期数量等于预期 (db);虚拟内存和堆大小也几乎相同。这就引出了一个问题:为什么任务管理器显示的数字大不相同?

标签: c# list datagridview backgroundworker


【解决方案1】:

有趣的是 - 遵循 Henk 的建议并使用了真正的分析器(.Net Memory Profiler)而不是任务管理器。

虽然内存使用数量几乎相同,但在同步和异步情况下,MyDataObj 实例的预期数量等于预期 (db),虚拟内存和堆大小也非常接近......仍然是 好奇 em> 正在进行中。 ntdll 对 VirtualAlloc() 的调用总是存在 1.5MB 的差异。其中大约 1MB 来自 DllUnregisterServerInternal(),在异步情况下占用 18.7MB(与 17.7MB 相比)。其余大部分来自 CoUninitializeEE(),它在异步版本中被调用,但不被同步应用程序调用 (?)。我知道,这是在深挖泥巴——抱歉。上面的 1.5MB 是我能找到的唯一真正的区别 - 只是我的疯狂猜测,它可能是其他事情发生的迹象。

真正的问题是:为什么任务管理器显示的数字大不相同?它不能很好地处理 BackgroundWorkers 吗?你有没有遇到过如此巨大的差异(30MB vs 80MB)?

【讨论】:

  • Dav,就 TaskManager 的内存使用量而言,50MB 是一个微小的差异。但在现实世界中它也很小,而且现代操作系统下的内存使用是一件非常复杂的事情。
  • 好吧,我想我不应该把它说成“巨大的差异”——我的意思是 80MB 是 30MB 的两倍多,并不是说消耗 80MB 的应用程序是一种资源消耗。也许您是对的 - 再次,我们有责任向客户介绍托管环境中的资源消耗估计。感谢您的所有输入 Henk,并保持头脑冷静。 (仍然很乐意将其提交给 MS 任务管理器团队,但这是另一回事!)
【解决方案2】:

我不完全确定这是否会有所帮助,但在 Async 方法中您可以更改:

List<MyDataObj> p;
using (MyL2SDb db = new MyL2SDb(MyConfig.ConnectionString))
{
    p = db.PRODUCTS
    .Select(p => new MyDataObj {Id = p.ID, Description = p.DESCR})
    .ToList();
}

Products = p;

到这里:

using (MyL2SDb db = new MyL2SDb(MyConfig.ConnectionString))
{
    Products = db.PRODUCTS
    .Select(p => new MyDataObj {Id = p.ID, Description = p.DESCR})
    .ToList();
}

我认为你不需要额外的列表变量。这可能是为什么?您正在创建一个完整的额外列表?无论哪种方式,这看起来也更干净一些:)

【讨论】:

  • 这不会导致问题;这是对同一列表的额外引用,不会复制任何对象。
  • 嗯......我刚刚意识到你在同步代码中做同样的事情......所以它可能不是那样的。但也许无论如何都要更改代码,看看它是否对两者都有帮助?
  • 感谢您的意见,但倾向于同意 SLaks,这绝对不是这里的问题。我更喜欢保留一个局部变量,在 using 内部分配它,并在 using 之外做任何其他需要做的事情。这样我就没有例如。里面有一个返回,恕我直言,这使得代码更易读/更容易理解。但这只是个人选择:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-18
  • 1970-01-01
  • 1970-01-01
  • 2015-08-28
  • 2021-06-29
  • 2012-11-21
相关资源
最近更新 更多