我尝试过一个简单的实验来验证垃圾收集器的功能.引用3.9关于.NET中自动内存管理的自动内存管理(MSDN).对我来说,它听起来像是C++中的共享指针.如果对象的引用计数器变为零,则它将被垃圾收集器解除分配.
所以我尝试在主窗体中创建一个函数.该函数在我的主窗体的Shown事件函数内调用,该函数在构造函数之后执行.这是实验代码.
public void experiment()
{
int[] a = new int[100000];
int[] b = new int[100000];
int[] c = new int[100000];
int[] d = new int[100000];
a = null;
b = null;
c = null;
d = null;
}
Run Code Online (Sandbox Code Playgroud)
以下是结果:
为什么垃圾收集器即使在设置为null之后也不释放由数组a,b,c,d分配的内存?
StackOverflow上的MSDN文档和许多答案都是为了解决正确实现的问题IDisposable
,例如MSDN IDisposable,MSDN实现IDisposable,优秀的StackOverflow Q&A
但是,它们似乎都没有涵盖我所拥有的更常见的用例:当我的班级有一个IDisposable
比一个方法更长的成员时该怎么办?例如
class FantasticFileService
{
private FileSystemWatcher fileWatch; // FileSystemWatcher is IDisposable
public FantasticFileService(string path)
{
fileWatch = new FileSystemWatcher(path);
fileWatch.Changed += OnFileChanged;
}
private void OnFileChanged(object sender, FileSystemEventArgs e)
{
// blah blah
}
}
Run Code Online (Sandbox Code Playgroud)
最接近的MSDN解决这个问题只涉及IDisposable
短时间实例的用例,所以调用Dispose
例如using
:
仅在直接使用非托管资源时才实现IDisposable.如果您的应用只使用实现IDisposable的对象,请不要提供IDisposable实现.相反,您应该在完成使用后调用对象的IDisposable.Dispose实现.
当然,这里不可能我们需要实例比方法调用更长时间存活!?
我怀疑这样做的正确方法是实现IDisposable
(将责任传递给我的类的创建者来处置它)但是没有所有的终结器和protected virtual void Dispose(bool disposing)
逻辑,因为我没有任何无人管理的资源,即:
class FantasticFileService : IDisposable
{
private FileSystemWatcher fileWatch; // FileSystemWatcher is IDisposable
public …
Run Code Online (Sandbox Code Playgroud) 我有一个类应该在处理或最终时删除一些文件.在终结器中我不能使用其他对象,因为它们可能已经被垃圾收集了.
我是否遗漏了关于终结器的一些观点并且可以使用弦乐?
UPD:类似的东西:
public class TempFileStream : FileStream
{
private string _filename;
public TempFileStream(string filename)
:base(filename, FileMode.Open, FileAccess.Read, FileShare.Read)
{
_filename = filename;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (_filename == null) return;
try
{
File.Delete(_filename); // <-- oops! _filename could be gc-ed already
_filename = null;
}
catch (Exception e)
{
...
}
}
}
Run Code Online (Sandbox Code Playgroud) 编辑:我的问题是没有得到我正在寻找的主要答案.我不清楚.我真的很想知道两件事:
Dispose()
导致内存泄漏?我的印象是,如果Dispose()
未在IDisposable
对象上调用内存泄漏.
根据这个帖子的讨论,我的看法不正确; 如果Dispose()
未调用,则不会发生内存泄漏.
那么为什么打扰Dispose()
呢?是否只是立即释放资源,而不是以后的某个时间?如果你有一个大型程序并且从不调用Dispose()
任何IDisposable
对象,那么最糟糕的事情是什么?
我正在使用数据库,有一种情况我想关闭它中的一个功能.关闭该功能看起来像这样......
DatabaseContext.Advanced.UseOptimisticConcurrency = false;
打开它也很容易.这个功能很好.但我对某事感到好奇,并想探索它......
是否有可能将它包装在"使用"块中,就像处理像dispose和unsafe这样的东西一样?例如...
using(DatabaseContext.Advanced.UseOptimisticConcurrency = false){
// do things!
}
// the feature is turned back on automatically here!
Run Code Online (Sandbox Code Playgroud)
在StackOverflow的优秀人才的帮助下,我现在已经完成了我想要的工作.再次感谢.这是我的工作代码.不要介意详细的文档.我只是那种在我脑海中输入所有内容的程序员.
using System;
namespace Raven.Client {
/// <summary>
/// Used to emulate a series of transactions without optimistic concurrency in RavenDB
/// </summary>
/// <remarks>
/// This has been flagged as an 'abuse' of the IDisposable interface, which is something I will learn more about
/// and try to find a better solution. The purpose of this …
Run Code Online (Sandbox Code Playgroud) 我阅读了解释如何使用Dispose模式的优秀答案,以及它为什么以这种方式工作.
该帖明确指出您希望在两种不同的场景中使用Dispose模式:
我的问题是:
我什么时候可以清理存储在C#中的静态变量中的对象?
我有一个懒惰的初始化静态变量:
public class Sqm
{
private static Lazy<Sqm> _default = new Lazy<Sqm>();
public static Sqm Default { get { return _default.Value; } }
}
Run Code Online (Sandbox Code Playgroud)
注:我已经只是改变Foo
成为一个static
类.如果Foo
是静态的,它不会以任何方式改变问题.但有些人确信,如果Sqm
没有先构建一个实例,就无法构造一个实例Foo
.即使我确实创造了一个Foo
物体; 即使我创建了100个,它也无法解决问题(何时"清理"静态成员).
样品用法
Foo.Default.TimerStart("SaveQuestion");
//...snip...
Foo.Default.TimerStop("SaveQuestion");
Run Code Online (Sandbox Code Playgroud)
现在,我的Sqm
类实现了一个方法,当不再需要该对象时必须调用该方法,并且需要自我清理(将状态保存到文件系统,释放锁等).必须在垃圾收集器运行之前调用此方法(即在调用对象的终结器之前):
public class Sqm
{
var values = new List<String>();
Boolean shutdown = false;
protected void Cleanup(ICollection stuff)
{
WebRequest http = new HttpWebRequest();
http.Open("POST", "https://stackoverflow.com/SubmitUsageTelemetry"); …
Run Code Online (Sandbox Code Playgroud) 我对所有关于IDispose和"使用"语句的讨论感到困惑.我想知道是否有人可以告诉我是否需要在以下测试示例中使用"using"语句或IDispose的某种实现...
public class Main()
{
MyFile myFile = new MyFile("c:\subdir\subdir2\testFile.txt");
Console.Writeline("File Name: " + myFile.FileName() + "File Size: " + myFile.FileSize());
}
public class MyFile
{
private FileInfo _fInfo;
public MyFile(string fullFilePath)
{
_fInfo = new FileInfo(fullFilePath);
}
public string FileName()
{
return _fInfo.Name;
}
public long FileSize()
{
return _fInfo.Length;
}
}
Run Code Online (Sandbox Code Playgroud) 可能重复:
使用块是否会关闭数据库连接?
db.Close()
以下是不必要的?
using (DbConnection db = GetDbConnection())
{
// do data-access stuff
// ...
db.Close();
}
Run Code Online (Sandbox Code Playgroud) 说我有一个公开的一类BeginLongOperation()
,并EndLongOperation()
用标准的方法开始/结束模式,并实现IDisposable
.
它是我的课负责处理一个呼叫Dispose()
的通话之间BeginLongOperation()
和EndLongOperation()
?
如果是这样,这样做的正确方法是什么?
c# ×10
.net ×7
dispose ×2
idisposable ×2
ado.net ×1
dbconnection ×1
memory-leaks ×1
singleton ×1
using ×1