在C++中,我习惯使用sentry模式来确保在块或函数退出时正确释放所获取的资源(例如,参见此处).例如,我使用它来获取图形状态,然后我可以做任何我想要的状态,当sentry对象(引用)超出范围时它会被放回去.
现在我正在使用C#,同样的技巧不起作用,因为析构函数不会被调用,直到谁知道 - 以后.
是否有一些OTHER方法可以保证在释放对象的最后一个引用时触发?或者我只需要记住在从我将使用哨兵的任何方法返回之前调用一些Restore()或Apply()或DoYourThing()方法?
目前,我正在优化大型批处理程序的内存使用情况。最多的内存由不同的数据表使用。例如,我的DataTable dataTable使用大约260MB。
就像线程接受的答案中的建议“ 在.NET DataTable中存储数据的内存开销是多少? ”,我正在尝试将相关数据移出DataTable。这是我的代码:
GC.Collect(); // force the garbage collector to free memory
// First stop point - Total process memory (taskmanager) = 900 MB
List<ExpandoObject> expandoList = new List<ExpandoObject>();
foreach (DataRow dataRow in dataTable.Rows)
{
dynamic expandoItem = new ExpandoObject();
expandoItem.FieldName = dataRow["FieldName"].ToString();
expandoList.Add(expandoItem);
}
// Second stop point - Total process memory (taskmanager) = 1055 MB
dataTable.Clear();
dataTable.Dispose();
dataTable = null;
GC.Collect(); // force the garbage collector to free memory
// Third stop point - …Run Code Online (Sandbox Code Playgroud) 我使用实体框架
public sealed class CacheManagementHelper
{
private readonly GJobEntities db = new GJobEntities();
public List<User> GetUsers()
{
return db.Users.ToList();
}
}
Run Code Online (Sandbox Code Playgroud)
并且 MS Visual Studio 2019 建议遵循
警告 CA1001 在“CacheManagementHelper”上实现 IDisposable,因为它创建了以下 IDisposable 类型的成员:“GJobEntities”。如果 'CacheManagementHelper' 之前已发布,则向此类型添加实现 IDisposable 的新成员被视为对现有使用者的重大更改。
我在这里找到了一些线索
但目前还不清楚我是否有实施IDisposable。
感谢帮助!
我只是C#的初学者.我正在使用XAMPP服务器用于MySQL数据库和Visual C#2010.然后我在phpMyAdmin中创建了一个名为"testdb"的数据库和一个名为"login"的表.我在表格中输入了用户名和密码.我正在做一个简单的WinForm登录,我在那里为用户名和密码以及一个按钮创建了两个文本框.我完成了我的代码并且没有编译器错误.但我在一条线上遇到了麻烦.它说"无法连接到任何指定的MySQL主机".我将MySql.Data添加到我的引用中.我想要在登录时获取数据库表中的数据.然后授权用户或如果不匹配,则会提示错误消息.
这是我的代码:
using MySql.Data.MySqlClient;
public bool Login(string username, string password)
{
MySqlConnection con = new MySqlConnection("host=localhost;username…");
MySqlCommand cmd = new MySqlCommand("SELECT * FROM login WHERE username='" +
username + "' AND password='" + password + "';");
cmd.Connection = con;
con.Open(); // This is the line producing the error.
MySqlDataReader reader = cmd.ExecuteReader();
if (reader.Read() != false)
{
if (reader.IsDBNull(0) == true)
{
cmd.Connection.Close();
reader.Dispose();
cmd.Dispose();
return false;
}
else
{
cmd.Connection.Close();
reader.Dispose();
cmd.Dispose();
return true;
}
}
else
{ …Run Code Online (Sandbox Code Playgroud) 我是C#的初学者,我不知道为什么这不起作用,我只想通过调用Dispose()方法将此对象设置为null .
为什么这不可能?
class MyClass:IDisposable
{
public void Dispose()
{
this = null;
}
}
Run Code Online (Sandbox Code Playgroud) 我SomeSingleton在C#中有一些类(如果重要,则为.NET 3.5)和代码:
foo()
{
...
SomeSingleton.Instance.DoSomething();
...
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:垃圾收集器什么时候会收集这个Singleton对象?
ps:SomeSingleton的代码:
private static SomeSingleton s_Instance = null;
public static SomeSingleton Instance
{
get
{
if (s_Instance == null)
{
lock (s_InstanceLock)
{
if (s_Instance == null)
{
s_Instance = new SomeSingleton();
}
}
}
return s_Instance;
}
}
Run Code Online (Sandbox Code Playgroud)
感谢帮助!
编辑(附说明):
在Widnows服务中我有代码:
...
FirstSingleton.Instance.DoSomething();
...
public class FirstSingleton
{
(Instance part the same as in SomeSingleton)
public void DoSomething()
{
SomeSingleton.Instance.DoSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
我想要实现的目标:我不关心FirstSingleton会发生什么,但SomeSingleton首先使用它启动Timer,所以我需要SomeSingleton存在(所以定时器可以在每个时间段运行新线程),只要我的服务是运行.
正如我从你的答案中理解的那样,所有这一切都会发生,因为对我的FirstSingleton和SomeSingleton的引用是静态的,并且在服务停止之前GC不会收集单身人士,我是对的吗?:)
StackOverflow上有几个关于如果我的对象管理其他实现的托管对象该怎么做的讨论System.IDisposable.
注意:下面我不是在讨论非托管代码.我完全理解清理非托管代码的重要性
大多数讨论都说如果你的对象拥有另一个实现的托管对象System.IDisposable,那么你也应该实现System.IDisposable,在这种情况下你应该调用Dispose()你的对象所持有的一次性对象.这是合乎逻辑的,因为您不知道您拥有的一次性对象是否使用非托管代码.你只知道另一个对象的创造者认为如果你Dispose不再需要这个对象就打电话会是明智的.
在社区维基编辑的StackOverflow中给出了对Disposable模式的一个非常好的解释:
很多时候,我在上面提到的链接中读到:
"你不知道两个对象被销毁的顺序.完全有可能在你的
Dispose()代码中,你试图摆脱的托管对象不再存在."
这让我感到困惑,因为我认为只要任何对象持有对象X的引用,那么对象X就不会也无法完成.
换句话说:只要我的对象持有对象XI的引用,就可以确定对象X没有最终确定.
如果这是真的,那么为什么会这样,如果我在完成之前持有对象的引用,我引用的对象已经完成了?
虽然我已经编写了一段时间,但我真的只是进入了我所谓的中级编码器.所以我理解dispose()的原理,即释放为变量和/或资源保留的内存.我也发现有时使用EF我必须dispose()以便其他操作正常工作.我不明白的只是需要发布的内容,何时使用dispose().
例如,我们不处理变量,如字符串,整数或布尔值.但是在某个地方我们越过"一条线",我们使用的变量和/或资源需要被处理掉.我不明白这条线在哪里.
在知道何时使用dispose()时,是否有一个原则或几个广泛的原则适用?
我阅读了这些SO帖子(具体情况,更多关于如何而不是何时)但我不觉得我理解何时使用dispose()的基础知识.我看到一条评论询问是否在变量超出范围时释放内存,这引起了我的注意,因为直到我看到响应为否,它才会因为超出范围而被释放,我会想到当它超出范围时它会被释放.我不想成为第二个链接中的一个人称为"无能的开发者",虽然我认为这有点苛刻.我们中的一些人还在学习.
所以这就是为什么我的问题是"什么决定何时真正需要处置?"
我的问题是少一个多么多的一个时候.当然评论如何有用,但即使调用dispose()的方法是一个Using语句,我仍然需要知道什么时候.
编辑原始问题: 我知道这是一个很长的解释,标记为重复的评论笔记请求,这不是一个咆哮,我只是不知道如何确保我专注于我的精确问题.很多时候,我们只是匆匆走过我们问的方式.正如我在这篇长篇文章的最后提到的那样,在我们专注于我的问题后,我将编辑所有这些,假设我们到达那里.根据我所读到的内容,我认为这是一个重要的问题.
提议的"答案"帖子是一篇很棒的帖子,但并没有真正回答我的问题.CodeNotFound下面的评论也提供了一个很好的链接,但它也没有真正回答我的问题.我提供了有关这些帖子的评论,以尝试帮助改进我的确切问题:
我什么时候应该在.NET中处理我的对象?:第一个答案以评论开头
一次性对象表示持有CLR本质上不知道的有价值资源的对象.
不幸的是,我不明白" 一次性对象...... CLR本质上没有意识到 " 这一术语包括在内. 这就是我要问的问题.我怎么知道某件事是否属于我必须处理的范畴?我们一直在代码中定义要使用的东西.我们何时越过这条线并成为我需要处置的对象()?顺便说一句,我注意到那篇文章的作者从未标出答案.我不知道这是否意味着他不觉得这个问题得到了回答,或者他的跟进是否很差,但我希望我能够提炼一点我希望了解的内容.当你仔细观察答案时,他们并没有真正解决哪些对象需要开发人员处理它们的问题,或者我如何知道如何识别哪些对象.我只是不知道我创建的对象或事物需要我负责处理.我认为GC和其他条款发挥作用,但同样,这就是方法.显而易见的是,大多数经验丰富的专业开发人员都知道他们创建的东西何时需要被处理掉.我不明白怎么知道那.
正确使用IDisposable界面:显然是一个流行的答案(1681 upvotes),但明确的答案开始于
Dispose的目的是释放非托管资源".
好的,但我的问题是如何通过查看它是非托管资源的东西来了解?我不理解以下说明如何应用到什么需要处置.
如果你在.NET框架中找到它,那么它就是托管的.如果你自己去探索MSDN,它是无人管理的 ...你现在负责清理它."
我不明白如何使用这种类型的解释来分类我需要处理的东西()和我不需要的东西..net框架中有各种各样的东西; 如何分离出需要我处理它们的东西?我该怎么看我告诉我我对此负责?
在那之后,这个答案就在约大篇幅讲了如何处置(),但我仍然停留在背什么需要处置.为了让这个话题进一步复杂化,该作者后来说:"现在我们将...
摆脱非托管资源(因为我们必须),和
摆脱托管资源(因为我们想要帮助)
所以现在我需要考虑处理一组使用内存的全新对象,我不知道它们是什么.该答案的作者后来说
对于任何喜欢这种答案风格的人(解释原因,如何变得明显)......
我理解作者是在暗示其他文章,但作者的建议是理解"为什么"使得"如何"显而易见并不合法,因为对一个人来说显而易见的事情对另一个人来说并不总是显而易见的.甚至在那时,作者更多地关注为什么以及如何,并且我的问题是什么时候,意味着什么需要被处理(),而不是当我完成它时.我知道当我做完事情时,我只是不知道 …
我有一个带析构函数的类,我得到一个空引用异常,因为我有时会销毁变量null.
这是null条件运算符在析构函数中的适当用法吗?
我甚至不确定这是否适合使用析构函数本身,因为它不是用于处理它所调用的实际对象而是用于处理它的变量.
~clsSAPSettings()
{
mtbTemp?.Close();
}
Run Code Online (Sandbox Code Playgroud)
这段代码是从VB6转换而来的,所以我想弄清楚如何处理这个问题.欢迎任何信息.
编辑:该类mtbTemp属于implements,IDisposable但没有 finaliser/desctructor.它只是关闭ORM模型中使用的连接.
对于任何人在详细解释后,我找到了一个很好的答案,正确使用IDisposable接口,它详细介绍了终结器的使用以及垃圾收集实际如何工作.
编辑 - 根据答案重命名为终结器
我试图在终结器中做一些事情,但程序在我完成之前终止。为了模拟,我做了以下测试,最多打印 20
这是否意味着 .NET 终结器在 2 秒后“超时”?
~MyClass()
{
// do some cleaup
int i = 0;
while (true)
{
Console.WriteLine(i++);
Thread.Sleep(100);
}
}
Run Code Online (Sandbox Code Playgroud)
对于上下文,我有一些后台线程(任务对象),我想优雅地终止它们。我只是测试一下从终结器完成它需要多长时间。
有什么更好的设计模式可以做到这一点?也许有一个“关闭”方法,我必须确保在关闭表单时调用该方法?我知道终结器是为了清理非托管内存,但停止所有线程似乎很好,因为我知道它将被调用。
也许我只是让线程突然终止而不用担心?