如何在构建非重组三叉树时避免c#中的System.OutOfMemoryException

时间:2014-01-09 15:18:24

标签: c# list memory-management out-of-memory

我已经“成功”实施了一个非重组三叉树来定价某些固定收益衍生品。 (如下图所示 - 但有三个分支没有重新连接)this picture

不幸的是,事实证明我可以使用的节点数量受可用内存的严重限制。如果我构建一个具有20个时间步长的树,则会产生3 ^ 19个节点(所以1,1亿个节点)

每个时间步的节点都保存在List<Node>中,这些数组存储在Dictionary<double,List<Node>>

每个节点都通过new Node(...)实例化。我还通过new Class()实例化每个列表和字典。也许这是我的错误的来源。

由于Dictionary / List-Object很大(通常就是这种情况),因此我没有抛出System.OutOfMemoryException因为我似乎有太多的节点 - 过了一会儿new Node(...)可以不再分配任何内存。最终,我认为最大2GB的List-Capacity也会出现 - 看看每个时间步长List的指数是如何增长的。

也许我的数据结构太浪费或者不适合手头的任务。

一种可能的解决方案是将树保存到文本文件中,从而完全避免内存问题。然而,这需要一个巨大的解决方法。

修改 添加更多背景。我需要树来定价路径依赖的产品。这意味着不幸的是我将不得不访问所有节点。在树木建成之后,我从树叶开始并及时倒退以确定价格。我也只生成了我需要的节点。

EDIT2: 我已经给出了一些主题,并且还考虑了各种反应。可能是我只需要将相应的树级别序列化到硬盘驱动器。所以基本上 - 我创建一个时间步骤(List<Node>)将其写入磁盘等。稍后当我从叶子开始 - 我将只需要反向加载它。

3 个答案:

答案 0 :(得分:3)

你基本上有两个选择。只评估你关心的分支(Andrew的收益)并且不存储结果构建你的树并将其保存到磁盘并在其上实现一个自定义集合接口来访问正确的部分磁盘。在这种情况下,您仍将在进程内存中保留最少量的数据,并依靠操作系统进行正确的磁盘缓存以快速访问。如果你开始使用大型数据集,第二个选项是一个很好的工具,可以在你的工具带中使用,所以你应该在考虑重用的情况下写这个。

答案 1 :(得分:2)

我们这里有一个经典的问题,即预先进行大量处理......然后将所有内容存储到内存中以便稍后处理。

虽然很简单,但考虑到条件非常恶劣(比如有十亿个条目),它会耗尽所有的记忆。

现在,OP没有真正说明树的意图是什么或者它将如何被使用......但我建议不要一次性构建它...根据需要构建它它

使用yield

进行懒惰评估

而不是一次性完成所有事情并且必须存储它......它可能是理想的,只有在你真正需要时才能这样做。有关使用yield

的更多信息和示例,请查看此post

如果你需要多次追踪这棵树,这将无法奏效......但它仍然可以让你拥有比现在更深的深度。

答案 2 :(得分:1)

我认为序列化到磁盘不会有太大帮助。一,当你试图反序列化列表时,你仍然会耗尽内存(据我所知,没有办法对一个对象进行部分反序列化)。

您是否考虑过将数据结构更改为关系数据库模型并将其存储在SQLEXPRESS数据库中?

这将为您提供使用索引而不是自定义树遍历逻辑执行查询的额外好处。