c# 析构函数(和终结器?)在我的程序结束时自动调用 - 我应该做些什么吗?
c# destructors (or finalisers?) called automatically at the end of my program - should I do somthing about that?
所以我一直在阅读大量关于如何处理内存分配和终结器等的帖子......我想我很清楚,直到我看到我从 运行 我的程序中获得的调试.该程序本身位于安全网络上,我的 "internet access" PC 没有 C#,因此下面未经测试的示例可能不会给出完全相同的行为,但希望能够展示我所看到的:
我有两个文件:
cli.cs
for (int i = 1; i <= 3; i++)
{
Console.WriteLine("------ ITERATION " + i + "------");
Regression.Tests.FileOperations.runTest();
}
Console.WriteLine("Test Finished");
FileOperations.cs
class FileOperations
{
Obj1 obj1 = null;
Obj2 obj2 = null;
public void doStuff()
{
// Clear the objects
obj1 = null;
obj2 = null;
// Create the objects
obj1 = new Obj1();
obj2 = new Obj2();
// do stuff (in this case just sleep for 5 seconds)
Thread.Sleep(5000);
}
// Static function so its can be called without instance
static public void runTest()
{
FileOperations fileOps = new FileOperations();
fileOps.doStuff();
}
}
- 所以在cli.cs中我们在循环中调用静态函数runTest()
迭代 3 次。
- runTest() 实例化一个 FileOperations 对象并
然后调用它的 doStuff() 函数。
- doStuff() 通过将所有以前的对象设置为空来清除它们(我读到这是这样做的方法)。然后它创建对象的新实例以供使用。
所以我对此进行了测试,似乎一切正常。但是我程序的输出给了我这个调试:
------ ITERATION 1 ------
------ ITERATION 2 ------
------ ITERATION 3 ------
Test Finished
~Obj1()
~Obj2()
~Obj1()
~Obj2()
~Obj1()
~Obj2()
所以,如果我正确地清除了对象(我可能不是?)为什么我的所有 Obj1 和 Obj2 都只在程序结束时被删除? - 也许这是正确的? - 我还没有找到任何具有相同输出的人的例子...
您只有 3 次迭代,因此在您的程序中没有很多时间点可能会发生垃圾回收。因此,即使 GC 会启动 三次 (我在这个小场景中对此表示怀疑),您也无法确定这种情况是否发生在 之前 下一次迭代或只是 在 所有这些之后。 GarbageCollection 的过程非常复杂,尤其是不确定的,因此您无法确定 确切地 何时从内存中释放实例。
虽然您有三个不同的 FileOperations
实例,它们拥有自己的 Obj1
和 Obj2
实例,但这些实例可能会或可能不会保留在堆中,直到 GC 最终决定开始。这至少会在您的应用程序终止时发生,但通常会更早。您 可以 对 GC 的唯一期望是它 将 运行。 GC 在另一端工作的 最频繁 点是当实例超出范围并且不再存在对该实例的引用时。在您的情况下,这是您的代码中不再使用 FileOperations
的实例的时候。
所以在你的场景中你有或多或少的两个选择:
- GC 在每次迭代或至少 一些 迭代中工作,至少比你的应用程序终止早得多
- 当您的应用终止时
由于您的程序非常小,因此出现第二种选择的可能性非常高。顺便说一句,这提高了整体性能,因为 GC 不需要一直工作 - 或者特别是释放任何实例 - 只需要几次(或者在你的情况下可能是一次)。
GC 做你的清理不使用终结器你可以使用终结器当你想为你的 class 实现一次性模式并覆盖处置方法我在我的 github 回购中做到了
https://github.com/garapricot/MVCBookStore/blob/master/DAL/Services/BookService.cs
所以我一直在阅读大量关于如何处理内存分配和终结器等的帖子......我想我很清楚,直到我看到我从 运行 我的程序中获得的调试.该程序本身位于安全网络上,我的 "internet access" PC 没有 C#,因此下面未经测试的示例可能不会给出完全相同的行为,但希望能够展示我所看到的:
我有两个文件:
cli.cs
for (int i = 1; i <= 3; i++)
{
Console.WriteLine("------ ITERATION " + i + "------");
Regression.Tests.FileOperations.runTest();
}
Console.WriteLine("Test Finished");
FileOperations.cs
class FileOperations
{
Obj1 obj1 = null;
Obj2 obj2 = null;
public void doStuff()
{
// Clear the objects
obj1 = null;
obj2 = null;
// Create the objects
obj1 = new Obj1();
obj2 = new Obj2();
// do stuff (in this case just sleep for 5 seconds)
Thread.Sleep(5000);
}
// Static function so its can be called without instance
static public void runTest()
{
FileOperations fileOps = new FileOperations();
fileOps.doStuff();
}
}
- 所以在cli.cs中我们在循环中调用静态函数runTest() 迭代 3 次。
- runTest() 实例化一个 FileOperations 对象并 然后调用它的 doStuff() 函数。
- doStuff() 通过将所有以前的对象设置为空来清除它们(我读到这是这样做的方法)。然后它创建对象的新实例以供使用。
所以我对此进行了测试,似乎一切正常。但是我程序的输出给了我这个调试:
------ ITERATION 1 ------
------ ITERATION 2 ------
------ ITERATION 3 ------
Test Finished
~Obj1()
~Obj2()
~Obj1()
~Obj2()
~Obj1()
~Obj2()
所以,如果我正确地清除了对象(我可能不是?)为什么我的所有 Obj1 和 Obj2 都只在程序结束时被删除? - 也许这是正确的? - 我还没有找到任何具有相同输出的人的例子...
您只有 3 次迭代,因此在您的程序中没有很多时间点可能会发生垃圾回收。因此,即使 GC 会启动 三次 (我在这个小场景中对此表示怀疑),您也无法确定这种情况是否发生在 之前 下一次迭代或只是 在 所有这些之后。 GarbageCollection 的过程非常复杂,尤其是不确定的,因此您无法确定 确切地 何时从内存中释放实例。
虽然您有三个不同的 FileOperations
实例,它们拥有自己的 Obj1
和 Obj2
实例,但这些实例可能会或可能不会保留在堆中,直到 GC 最终决定开始。这至少会在您的应用程序终止时发生,但通常会更早。您 可以 对 GC 的唯一期望是它 将 运行。 GC 在另一端工作的 最频繁 点是当实例超出范围并且不再存在对该实例的引用时。在您的情况下,这是您的代码中不再使用 FileOperations
的实例的时候。
所以在你的场景中你有或多或少的两个选择:
- GC 在每次迭代或至少 一些 迭代中工作,至少比你的应用程序终止早得多
- 当您的应用终止时
由于您的程序非常小,因此出现第二种选择的可能性非常高。顺便说一句,这提高了整体性能,因为 GC 不需要一直工作 - 或者特别是释放任何实例 - 只需要几次(或者在你的情况下可能是一次)。
GC 做你的清理不使用终结器你可以使用终结器当你想为你的 class 实现一次性模式并覆盖处置方法我在我的 github 回购中做到了 https://github.com/garapricot/MVCBookStore/blob/master/DAL/Services/BookService.cs