gpt4 book ai didi

c# - TPL 任务 + 动态 == OutOfMemoryException?

转载 作者:太空狗 更新时间:2023-10-30 01:22:44 25 4
gpt4 key购买 nike

我正在开发一个流式 Twitter 客户端 - 在持续运行 1-2 天后,我的内存使用量 >1.4gigs(32 位进程),在达到该数量后不久,我将获得一个本质上是这样的代码出现内存不足异常(这段代码将在 <30 秒内在我的机器上出错):

while (true)
{
Task.Factory.StartNew(() =>
{
dynamic dyn2 = new ExpandoObject();

//get a ton of text, make the string random
//enough to be be interned, for the most part
dyn2.text = Get500kOfText() + Get500kOfText() + DateTime.Now.ToString() +
DateTime.Now.Millisecond.ToString();
});
}

我已经对它进行了概要分析,这肯定是由于 DLR 中的类下降(根据内存 - 我在这里没有我的详细信息)xxRuntimeBinderxx 和 xxAggregatexx。

This answer from Eric Lippert (microsoft)似乎表明我正在幕后制作表达式解析对象,即使在我的代码中没有保留对任何内容的引用,这些对象也永远不会被 GC。

如果是这种情况,上面的代码中是否有某种方法可以防止或减轻它?

我的后备方案是消除动态使用,但我不想这样做。

谢谢

更新:

2012 年 12 月 14 日:

答案:

这个特定示例释放其任务的方法是产生 (Thread.Sleep(0)),这将允许 GC 处理释放的任务。我猜在这种特殊情况下不允许处理消息/事件循环。

在我使用的实际代码中(TPL 数据流),我没有在 block 上调用 Complete(),因为它们本来就是成为一个永无止境的数据流——只要 Twitter 发送它们,任务就会接收 Twitter 消息。在此模型中,没有任何理由告诉任何 block 它们已完成,因为只要应用程序正在运行,它们就永远不会BE完成。

不幸的是,数据流 block 似乎从未设计为长时间运行或处理无数的项目,因为它们实际上保留了对发送到其中的所有内容的引用。如果我错了,请告诉我。

因此解决方法是定期(根据您的内存使用情况——我的是每 10 万条推特消息)释放 block 并重新设置它们。

在这个方案下,我的内存消耗永远不会超过 80megs,在回收 block 并强制 GC 进行良好测量后,gen2 堆回到 6megs,一切都很好。

2012 年 10 月 17 日:

  • “这没有做任何有用的事情”:这个例子只是为了允许你快速产生问题。它是从几个一百行与问题无关的代码。
  • 无限循环创建任务并依次创建对象”:记住 - 这只是快速演示问题 - 实际代码正等待更多的流数据。另外 - 查看代码 - 所有对象都是在任务中的 Action<> lambda 中创建的。为什么在它超出范围后不(最终)清理它?问题也不是因为做得太快 - 实际代码需要一天多的时间才能到达内存不足异常 - 这只是让它足够快来尝试。
  • “任务是否保证被释放?”一个对象就是一个对象,不是吗?我的理解是,调度程序只是在池中使用线程,它正在执行的 lambda 无论如何都会在它运行完后被丢弃。

最佳答案

与 DLR 相比,这更多地与生产者远远领先于消费者有关。循环尽可能快地创建任务 - 并且任务不会“立即”启动。很容易弄清楚它可能落后多少:

        int count = 0;

new Timer(_ => Console.WriteLine(count), 0, 0, 500);

while (true)
{
Interlocked.Increment(ref count);

Task.Factory.StartNew(() =>
{
dynamic dyn2 = new ExpandoObject();
dyn2.text = Get500kOfText() + Get500kOfText() + DateTime.Now.ToString() +
DateTime.Now.Millisecond.ToString();

Interlocked.Decrement(ref count);
});
}

输出:

324080
751802
1074713
1620403
1997559
2431238

对于 3 秒的调度来说,这已经很多了。删除 Task.Factory.StartNew(单线程执行)产生稳定的内存。

不过,您提供的复制似乎有点做作。如果太多并发任务确实是你的问题,你可以尝试 custom task scheduler that limits concurrent scheduling .

关于c# - TPL 任务 + 动态 == OutOfMemoryException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12940314/

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