需要删除对象:在函数中实现Dispose或创建对象
本文关键字:实现 Dispose 创建对象 函数 删除 对象 | 更新日期: 2023-09-27 18:00:25
我有一些对象可以读取文件、将数据保存在数组中并进行一些操作。顺序是创建对象A,与对象A一起操作。创建对象B,与对象B一起操作。。。每个对象读取的数据可以是大约10MB。因此,最好的选择是在对每个对象进行操作后删除每个对象。比方说,我希望我的程序分配大约10MB的内存,而不是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()
{
...
}
}
我的问题是:我应该执行dispose吗?做一些类似的事情:
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());
}
...
我读到,当您使用未命令的资源(套接字、流…)时,建议实现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());
}
IDisposable
等在这里对您没有帮助,因为它不会导致任何内容被收集。在这种情况下,最好的方法可能是使用池来减少分配——本质上是成为您自己的内存管理器。例如,如果您的List<string>
很大,那么您可以通过重新使用列表来避免很多数组——显然是在清除列表之后。如果调用.Clear()
,则后备阵列不会重置——它只是设置一个逻辑标记,将其视为空。在您的特定情况下,您的许多对象将是单独的string
;这更为棘手,但至少它们很小,应该在零世代可以收藏。
在您的情况下,我会分配一个缓冲区数组。例如,分配一次10MB的阵列,然后用所需的数据填充它。然后,当您到达下一个对象时,只需重用该数组。如果您需要一个更大的数组,您可以分配一个新的、更大的阵列,然后使用它。垃圾收集器最终会移除较小的垃圾收集器。
你也可以使用List<T>
,它会在内部做同样的事情(分配一个数组,保持它直到它变得太小,分配一个新的)。在创建下一个对象之前只Clear
它。
请注意,不能强制垃圾收集器1收集对象。IDisposable
实际上只用于清理非托管资源,因为垃圾收集器不知道这些资源,或者关闭(文件)句柄。调用Dispose
并不保证(或暗示)对象已从内存中删除。
但是,如果您什么都不更改,您的代码仍然是正确的,并且可以正常工作。垃圾收集器负责在任何时候删除未使用的对象,并确保始终有足够的内存可用。要让收集器完成它的工作,唯一需要做的就是放弃对旧对象的任何引用(通过覆盖它们或将它们设置为null
,或让它们超出范围)。
1)您可以通过调用GC.Collect()
来强制垃圾收集器收集数据。但是,不建议使用。让垃圾收集器自己解决。
如果您使用的是.NET 4.0或更高版本,请查看BlockingCollection类。使用Int32参数的构造函数可以指定集合大小的上限。Add和Take方法起节流阀的作用。只有在尚未达到上限的情况下,添加才会成功。如果有,它就会阻塞。只有当项目存在时,Take才会成功。如果没有项目存在,它将被阻止,直到有一个可用。当然,该类有这些方法的一些变体,因此请全面检查文档,看看哪些方法(如果有的话)有意义。