2013-02-22 71 views
7

我有一些读取文件的对象,将数据保存在数组中并进行一些操作。序列是创建对象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资源(套接字,流,...)的建议,但在我的课,我只有大数据阵列。

另一种方式是为每个对象创建函数(我想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

我编辑了你的标题。请参见“[应的问题包括‘标签’,在他们的头衔?(http://meta.stackexchange.com/questions/19190/)”,这里的共识是“不,他们不应该”。 – 2013-02-22 02:04:00

回答

5

IDisposable等不会帮助你在这里,因为它不会引起任何要收集的东西。在这种情况下,最好的方法是使用来减少分配 - 实质上成为您自己的内存管理器。例如,如果您的List<string>很大,您可以通过重新使用列表来避免很多阵列 - 显然在清除它们之后。如果您拨打.Clear(),支持数组不会重置 - 它只是设置一个逻辑标记以将其视为空。在你的具体情况下,你的很多对象将成为个人string s;这是棘手的,但至少它们很小,应该可以在零代收集。

+1

如果你想调整后备数组的大小,你可以在调用Clear()后设置'Capacity = someValue'。 (请注意,它不会允许您将“容量”降低到当前大小以下,因此您必须先清除它。) – porges 2013-02-22 02:12:26

+0

重复使用列表是一个不错的主意,但在我的情况下很复杂。我从一些CSV文件中读取数据。对于每个csv,我提取数据列(每列的字符串列表)并创建一些图。重新使用每个csv读取数据的列表很容易实现。但是,重新列出每个csv的列是更复杂的。一个csv可能有3列(3列表),antoher 8列(8列表),所以我必须创建尽可能多的列表作为csv可能具有的最大列数。然后为每个列重新列出每个列表..一个复杂的代码。用colums删除每个对象会更容易:) – Alberto 2013-02-28 12:53:51

3

在你的情况下,我会分配一个缓冲区数组。例如,分配一个10 MB的阵列一次,并填充所需的数据。然后,当你到达下一个对象时,只需重新使用该数组。如果你需要更大的数组,你可以分配一个新的,更大的数组,然后使用它。垃圾收集器将最终删除您的较小的一个。

你也可以使用一个List<T>,它会在内部做相同的事情(分配一个数组,保持它,直到它变得太小,分配一个新的)。只需Clear它在创建下一个对象之前。

请注意,您不能强迫 垃圾收集器收集的对象。 IDisposable实际上只用于清理非托管资源,因为垃圾收集器不知道它们,或者关闭(文件)句柄。调用Dispose不保证(或暗示)该对象已从内存中移除。

但是,如果你什么也没有改变,你的代码仍然是正确的,并且正常工作。垃圾收集器负责删除未使用的对象,只要感觉这样做,它就会确保在任何时候都有足够的可用内存。让收藏者完成工作的唯一方法是放弃对旧对象的引用(通过覆盖它们或将其设​​置为null,或让它们超出范围)。

)您可以强制垃圾收集器通过调用GC.Collect()来收集数据。但是,建议使用而不是。让垃圾收集器自己弄清楚。

0

如果您使用.NET 4.0或更高版本,请查看BlockingCollection类。 constructor that takes the Int32 parameter允许您指定集合大小的上限。方法AddTake作为节流阀工作。如果尚未达到上限,则添加将成功。如果有,它会阻止。只有当物品存在时,Take才会成功。如果没有项目存在,它将阻塞,直到有一个可用。当然,这个类有这些方法的一些变体,所以要全面检查文档以查看哪些(如果有的话)是有意义的。