我有一些对象读取文件,将数据保存在数组中并进行一些操作。序列是Create对象A,用对象A操作。创建对象B,用对象B操作... 每个对象读取的数据可能约为10 MB。因此,最好的选择是在每个对象操作后删除每个对象。假设我希望我的程序在内存中分配大约10 MB,而不是10MB * 1000对象= 1GB
对象类似于:
class MyClass
{
List<string[]> data;
public MyClass(string datafile)
{
using (CsvReader csv = new CsvReader(new StreamReader(datafile), true))
{
data = csv.ToList<string[]>();
}
}
public List<string> Operate()
{
...
}
}
我的问题是:我应该实施处置吗?做一些像:
List<string> results = new List<results>();
using (MyClass m = new MyClass("fileM.txt"))
{
results.AddRange(m.Operate());
}
using (MyClass d = new MyClass("fileD.txt"))
{
results.AddRange(d.Operate());
}
...
我已经读过,当你使用unmmanaged资源(套接字,流,...)时,建议实现Disposable,但在我的类中我只有大数据数组。
另一种方法是为每个对象创建函数(我想GC会自动删除函数中创建的对象):
List<string> results = new List<results>();
results.AddRange(myFunction("fileM.txt"));
results.AddRange(myFunction("fileD.txt"));
public List<string> myFunction(string file)
{
MyClass c = new MyClass(file);
return results.AddRange(c.Operate());
}
答案 0 :(得分:5)
IDisposable
等在这里不会帮助你,因为它不会导致任何收集。在这种情况下,最好的方法可能是使用池来减少分配 - 基本上成为您自己的内存管理器。例如,如果您的List<string>
很大,那么通过重新使用列表可以避免很多阵列 - 显然是在清除它们之后。如果您调用.Clear()
,则不会重置后备阵列 - 它只是设置一个逻辑标记以将其视为空。在您的特定情况下,您的许多对象将成为个人string
;这比较棘手,但至少它们很小,应该可以在第0代收集。
答案 1 :(得分:3)
在你的情况下,我会分配一个缓冲区数组。例如,分配一个10 MB的数组,并用您想要的数据填充它。然后,当你到达下一个对象时,只需重用该数组。如果你需要一个更大的数组,你可以只分配一个更大的新数组,然后使用它。垃圾收集器最终将删除较小的垃圾收集器。
你也可以使用List<T>
,它会在内部做同样的事情(分配一个数组,保持它直到它变得太小,分配一个新数组)。在创建下一个对象之前只需Clear
。
请注意,您无法强制 1 垃圾收集器来收集对象。 IDisposable
确实只用于清理非托管资源,因为垃圾收集器不知道它们,或者关闭(文件)句柄。调用Dispose
并不能保证(或暗示)该对象已从内存中删除。
但是,如果您不做任何更改,您的代码仍然是正确的并且正常工作。垃圾收集器负责在发生这种情况时删除未使用的对象,并确保始终有足够的可用内存。让收集器完成其工作所要做的唯一事情就是放弃对旧对象的任何引用(通过覆盖它们或将它们设置为null
,或让它们超出范围)。
1 )您可以通过调用GC.Collect()
强制垃圾收集器收集您的数据。但是,建议不要 。让垃圾收集器自己搞清楚。
答案 2 :(得分:0)
如果您使用的是.NET 4.0或更高版本,请查看BlockingCollection类。 constructor that takes the Int32 parameter允许您指定集合大小的上限。 Add和Take方法可用作限制器。只有在尚未达到上限时才会成功添加。如果有,它会阻止。只有项目存在时,才会成功。如果没有项目,它将阻止,直到有一个项目可用。当然,这个类有一些这些方法的变体,所以要仔细检查文档,看看哪些有意义。