繁体   English   中英

C#:BackgroundWorker克隆资源?

[英]C#: BackgroundWorker cloning resources?

问题

我两天来一直在努力解决这个问题,而且只是用尽了想法。 一点......背景:我们有一个WinForms应用程序需要访问数据库,从该数据构造相关的内存中对象列表,然后显示在DataGridView上。 重要的一点是,我们首先填充应用程序范围的缓存(List),然后为DGV所在的表单创建本地缓存的镜像(使用List构造函数参数)。

因为获取数据需要花费几秒钟(DB位于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会因两个线程而丢失? 或者是任务管理器显示不正确的值?

对任何回应,建议和批评都会很有信心。

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

虽然mem使用数字几乎相同,但是在同步和异步情况下,MyDataObj实例的预期数量等于预期的(db),虚拟内存和堆大小也非常接近......仍然有些奇怪的事情正在发生。 由于ntdll对VirtualAlloc()的调用,总有1.5MB的差异。 其中大约1MB来自DllUnregisterServerInternal(),在异步情况下占用18.7MB(相对于17.7MB)。 其余大多数来自CoUninitializeEE(),它在异步版本中调用,但不会被同步应用程序调用(?)。 我知道,这是深陷泥潭 - 道歉。 以上1.5MB是我能找到的唯一真正的区别 - 只是我猜测它可能是其他事情发生的迹象。

真正的问题是 :为什么任务经理显示出截然不同的数字? 它不能很好地处理BackgroundWorkers吗? 您是否遇到过如此巨大的差异(30MB对80MB )?

我不完全确定这是否会有所帮助,但在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();
}

我不认为你需要额外的列表变量。 那可能是为什么? 你正在创建一个额外的列表? 无论哪种方式,这也是一个更清洁的看:)

暂无
暂无

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

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