gpt4 book ai didi

c# - .net 框架 4 中的高内存问题,但框架 4.5 中没有

转载 作者:太空狗 更新时间:2023-10-29 18:27:21 26 4
gpt4 key购买 nike

我有以下一段代码(.net 4)消耗大量内存:

struct Data
{
private readonly List<Dictionary<string,string>> _list;

public Data(List<Dictionary<string,string>> List)
{
_list = List;
}

public void DoWork()
{
int num = 0;
foreach (Dictionary<string, string> d in _list)
{
foreach (KeyValuePair<string, string> kvp in d)
num += Convert.ToInt32(kvp.Value);
}

Console.Write(num);

//_list = null;
}
}

class Test1
{
BlockingCollection<Data> collection = new BlockingCollection<Data>(10);
Thread th;

public Test1()
{
th = new Thread(Work);
th.Start();
}

public void Read()
{
List<Dictionary<string, string>> l = new List<Dictionary<string, string>>();
Random r = new Random();

for (int i=0; i<100000; i++)
{
Dictionary<string, string> d = new Dictionary<string,string>();
d["1"] = r.Next().ToString();
d["2"] = r.Next().ToString();
d["3"] = r.Next().ToString();
d["4"] = r.Next().ToString();

l.Add(d);
}

collection.Add(new Data(l));
}

private void Work()
{
while (true)
{
collection.Take().DoWork();
}
}
}

class Program
{
Test1 t = new Test1();
static void Main(string[] args)
{
Program p = new Program();
for (int i = 0; i < 1000; i++)
{
p.t.Read();
}
}
}

阻塞集合的大小是 10。据我所知,gc 应该在其 DoWork 方法完成后立即收集 'Data' 结构中的引用。但是,内存会继续快速增加,直到程序崩溃或自行关闭,而且这种情况在低端机器上更常见(在某些机器上内存不会增加)。此外,当我添加以下行时“_list = null;”在 DoWork 方法结束并将“数据”转换为类(来自结构)时,内存不会增加。

这里会发生什么。我需要一些建议。

更新:问题发生在安装了 .net framework 4 的机器上(4.5 未安装 )

最佳答案

如果您阅读 Stephen Toub's explanation如何ConcurrentQueue有效,这种行为是有道理的。 BlockingCollection用途 ConcurrentQueue默认情况下,它将其元素存储在 32 个元素段的链表中。

出于并发访问的目的,链表中的元素永远不会被覆盖,因此在整个 32 段的最后一个被消耗之前它们不会被取消引用。由于您有 10 个元素的有界容量,假设您生产了 41 个元素并消耗了 31 个。这意味着您将有一个包含 31 个消耗元素和一个排队元素的片段,以及另一个包含剩余 9 个元素的片段。此时所有 41 个元素都被引用,因此如果每个元素是 25MB,您的收藏将占用 1GB!一旦消费了下一个项目,head 段中的所有 32 个元素都将被取消引用并且可以被收集。

您可能认为队列中应该只需要 10 个元素,对于非并发队列就是这种情况,但这不允许一个线程在另一个线程正在生产或消费时枚举队列中的元素元素。

.Net 4.5 框架没有泄漏的原因是,只要没有人枚举队列,它们就会改变行为,以便在元素一产生就将其清空。如果你开始枚举 collection ,即使使用 .Net 4.5 框架,您也应该会看到内存泄漏。

设置的原因_list = null当您有 class 时有效是您正在创建一个“盒子”包装器,它允许您在每个使用它的地方取消引用列表。在本地变量中设置值会更改队列引用的同一个副本。

设置的原因_list = null当您有 struct 时不起作用是您只能更改 struct 的副本.位于该队列段中的“原始”版本实际上是不可变的,因为 ConcurrentQueue没有提供改变它的方法。换句话说,您只更改本地变量中值的副本,而不是更改队列中的副本。

关于c# - .net 框架 4 中的高内存问题,但框架 4.5 中没有,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14352480/

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