在 PHP 类中,解析器处理__construct和__destruct方法来实例化实例并在脚本退出或使用 unset 时销毁它。当您扩展一个类时,您只需使用parent::__construct和parent::__destruct来运行可能需要在扩展的类上运行的任何清理代码。
现在,在表示数据库数据并帮助您操作该数据的类的上下文中,我认为__destruct可以使用一种方法来将当前值与从数据库中获取的原始值进行比较,并在必要时进行更新(在某些情况下总是如此)只要主键值无法更改,就进行更新)。在 PHP 中实现这一点非常简单。
这种方法的主要优点是根据需要快速简单地操作类变量,然后让类在最后进行一次大的更新。在运行几分钟的长脚本中,最好在 __construct 期间创建数据库实例、获取数据、关闭数据库连接,然后仅在几分钟的长时间执行期间操作类变量。在 __destruct 上,打开一个新的数据库连接进行更新,然后关闭数据库连接并清理任何其他需要清理的内容。
我很好奇人们对这是否是一个好主意/坏做法的想法,但我的主要问题是这在 Ruby 中是否可能。
在 Ruby 中,您可以在实例化类的实例时运行初始化方法。Ruby 中的等效项parent::__construct是superRuby。Ruby 类有ObjectSpace.define_finalizeand方法。finalize但是,据我了解,finalize 方法不应该能够引用调用它的实例。最重要的是,我找不到任何与parent::__destruct. 我怀疑这是因为没有等效的方法,因为该finalize方法似乎是明确设计来防止引用本身的。
那里有人知道如何做到这一点吗?如果不是,转储 Ruby 类以取回资源并防止数据丢失的最佳实践是什么?是否每个人都有一个在将类实例设置为 nil 之前调用的 Garbage_collection 方法,或者还有其他方法吗?
谢谢
嗨,我在这里有代码,我不明白为什么我会遇到断点(请参阅评论)。
这是我不知道或我不正确理解的 Microsoft 错误吗?
代码在 Debug 中进行了测试,但我认为它不应该改变任何东西。
注意:您可以直接在控制台应用程序中测试代码。
仅供参考...在 supercat 回答之后,我使用建议的解决方案修复了我的代码,并且效果很好:-) !!! 不好的是静态字典的使用和性能随之而来但它的工作原理。...几分钟后,我意识到 SuperCat 给了我所有的提示,让我做得更好,解决静态字典,我做到了。代码示例是:
样品...
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace WeakrefBug
{
// **********************************************************************
class B : IDisposable
{
public static List<B> AllBs = new List<B>();
public B()
{
AllBs.Add(this);
}
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
AllBs.Remove(this);
disposed = true;
}
}
~B() …Run Code Online (Sandbox Code Playgroud) 最近我们发现我们的服务器应用程序之一(因此它是 Windows 服务)因 OutOfMemory 异常而失败。我们试图找出发生了什么,但最终确定队列中的对象没有被最终确定,因此不会对它们进行垃圾回收。我们试图通过使用 Windbg 找出哪个终结器会导致这种行为,但我们无法找出究竟是哪个对象导致了这种行为。
通过使用 !finalizequeue 命令,我们可以发现这一点:
0:053> !finalizequeue
未加载 clr.dll 的 PDB 符号
要清理的同步块:0
将要发布的自由线程接口:0
要发布的 MTA 接口:0
待发布的STA接口:0
----------------------------------
第 0 代有 28 个可终结对象(050eab4c->050eabbc)
第 1 代有 15 个可终结对象 (050eab10->050eab4c)
第 2 代有 658 个可终结对象 (050ea0c8->050eab10)
准备完成 3027 个对象 (050eabbc->050edb08)
...
3027 是一个非常高的数字(运行几分钟后,这个数字仍在增长并且从未下降)。我试图找出地址 050eabbc 上的对象,但它总是不同的类型,所以我认为这不是原因。
如果我尝试打印终结器线程的本机调用堆栈,则会得到以下信息:
0:053> ~2k
*** 错误:找不到符号文件。默认为 C:\Windows\SYSTEM32\KERNELBASE.dll 导出符号 -
ChildEBP RetAddr
警告:堆栈展开信息不可用。以下框架可能是错误的。
032ef09c 772f10b4 ntdll!ZwWaitForSingleObject+0xc
*** 错误:找不到符号文件。默认为 C:\Windows\SYSTEM32\combase.dll 导出符号 -
032ef0b0 755ff0b5 内核数据库!等待单个对象+0x12
032ef0e4 7554b22a combase!NdrOleDllGetClassObject+0x1399
032ef108 755ff10c combase!PropVariantCopy+0x177b
032ef224 75511724 … 我有一个ImageWrapper类将图像保存到磁盘中的临时文件以释放堆内存,并允许在需要时重新加载它们.
class ImageWrapper {
File tempFile;
public ImageWrapper(BufferedImage img) {
// save image to tempFile and gc()
}
public BufferedImage getImage() {
// read the image from tempFile and return it.
}
public void delete() {
// delete image from disk.
}
}
Run Code Online (Sandbox Code Playgroud)
我关注的是,如何确保文件在ImageWrapper垃圾收集时被删除(否则我冒着用不需要的图像填充磁盘的风险).这必须在应用程序仍在运行时完成(而不是终止时的清理建议),因为它可能会长时间运行.
我不完全熟悉java的GC概念,我想知道finalize()我是否正在寻找.我的想法是从override finalize()方法调用delete()(在一个单独的Thread上).这是正确的方法吗?
close()由于每个这样的图像被提取到我无法控制的侦听器列表,并且可能保存对该对象的引用,因此我认为我不能像许多用户所建议的那样使用该对象.我确定能够删除文件的唯一时间是没有引用,因此我认为finalize()是正确的方法.有什么建议?
什么是finalize()不会被调用的场景?如果唯一可能的是退出程序(以预期/意外的方式),我可以接受它,因为这意味着我只冒一个不需要的临时文件(在退出期间处理的文件).
这是一个相当不错的观点,我希望答案是"开始时并不是一个好主意" - 也就是说,如果某人有点放纵,它有一个我感兴趣的点.
型号代码:
public partial class MyEntities : ObjectContext
{
// the idea is if the object is in a using block, this always gets called?
protected override void Dispose(bool disposing)
{
this.SaveChanges();
base.Dispose(disposing);
}
}
Run Code Online (Sandbox Code Playgroud)
客户代码:
using(var model = new MyEntities())
{
// do something
// no worry about calling model.SaveChanges()
}
Run Code Online (Sandbox Code Playgroud)
我不确定的问题是:
处置正确的地方是因为我出于某种原因想到"终结" - 我总是对C#破坏感到困惑.
在客户端代码中抛出异常的情况下,通常会跳过SaveChanges并且这很好,但是如果我认为这是有效的,那么它总是会调用它.我应该尝试空捕获吗?
public partial class MyEntities : ObjectContext
{
protected override void Dispose(bool disposing)
{
try
{
this.SaveChanges();
}
catch {}
base.Dispose(disposing);
} …Run Code Online (Sandbox Code Playgroud)我可以看到已经有很多关于dispose与析构函数方法的线程,但我只想确保在继续之前我正确理解它们.
垃圾收集器是否隐式使用析构函数方法,以便何时不再引用对象(即不再需要),并配置我们开发人员使用的方法来显式处理可能无法由垃圾收集器处理的对象?
此外 - 我现在正在阅读所有这些,似乎这是一个或另一个与这些方法的情况.例如,给出以下代码:
class DansClass : IDisposable
{
public void Dispose()
{
GC.SuppressFinalize(this);
Console.WriteLine("Disposing...");
}
-DansClass()
{
Console.WriteLine("Destructing...");
}
}
Run Code Online (Sandbox Code Playgroud)
输出将是:
解构...
可以理解,因为我们已经抑制了finalize(析构函数)所以我们只看到Dispose输出.
但是,如果我注释掉SuppressFinalize()方法,则输出为:
处置......
为什么析构函数不被称为?
我对finalize方法有疑问.如果我有很多具有许多继承的类,那么当应用程序关闭时如何调用所有finalize方法?
这是一个展示令人惊讶的终结行为的示例程序:
class Something
{
public void DoSomething()
{
Console.WriteLine("Doing something");
}
~Something()
{
Console.WriteLine("Called finalizer");
}
}
namespace TestGC
{
class Program
{
static void Main(string[] args)
{
var s = new Something();
s.DoSomething();
GC.Collect();
//GC.WaitForPendingFinalizers();
s.DoSomething();
Console.ReadKey();
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果我运行该程序,打印的是:
Doing something
Doing something
Called finalizer
Run Code Online (Sandbox Code Playgroud)
这似乎符合预期.因为在调用之后有一个对s的引用GC.Collect(),s不是垃圾.
现在从行//GC.WaitForPendingFinalizers();
构建中删除注释 并再次运行该程序.
我希望输出中没有任何改变.这是因为我读到如果发现对象是垃圾并且它有终结器,它将被放在终结器队列中.由于对象不是垃圾,因此它不应该放在终结器队列上似乎是合乎逻辑的.因此,注释掉的那条线应该什么都不做.
但是,该计划的输出是:
Doing something
Called finalizer
Doing something
Run Code Online (Sandbox Code Playgroud)
有人可以帮助我理解为什么终结器会被调用吗?
我知道Java中的终结器存在严重的性能问题 - 请参阅此主题以获取详细信息:为什么终结器会产生"严重的性能损失"?
现在我有一个场景,我想禁止某个类的子类有终结器.AfaIk,这可以通过添加最终的空终结器来完成:
protected final void finalize() throws Throwable {}
Run Code Online (Sandbox Code Playgroud)
这样一个空的终结器是否已经触发了已知的性能问题?或者GC会将其检测为空终结器并将对象视为普通的非终结对象吗?
原因是使用自己的受控终结过程的框架.实现上述类的子类的用户可以通过添加自己的Java终结器来破坏此过程.此外,如果需要完成,它将迫使他们使用预期的最终化过程.
我已经仔细阅读了这篇文章,并且似乎清楚地指出了在所有IDisposable实施情况下都应该实施处置模式。我试图理解为什么在我的班级仅持有托管资源(即其他IDisposable成员或安全句柄)的情况下需要实现处置模式的原因。为什么我不能写
class Foo : IDisposable
{
IDisposable boo;
void Dispose()
{
boo?.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
如果可以肯定地知道没有非托管资源,并且没有指向Dispose终结器调用方法的信息,因为托管资源没有从终结器中释放出来?
更新:为了增加一些清晰度。讨论似乎归结为以下问题:是否需要为每个实现的基础公共非密封类实现处置模式IDisposable。但是,当没有非托管资源的基类不使用dispose模式而具有非托管资源的子类确实使用此模式时,我找不到层次结构的潜在问题:
class Foo : IDisposable
{
IDisposable boo;
public virtual void Dispose()
{
boo?.Dispose();
}
}
// child class which holds umanaged resources and implements dispose pattern
class Bar : Foo
{
bool disposed;
IntPtr unmanagedResource = IntPtr.Zero;
~Bar()
{
Dispose(false);
}
public override void Dispose()
{
base.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void …Run Code Online (Sandbox Code Playgroud) finalizer ×10
c# ×6
java ×3
.net ×2
destructor ×2
dispose ×2
idisposable ×2
final ×1
performance ×1
ruby ×1
windbg ×1