如何删除该实例中的类的实例

本文关键字:实例 何删除 删除 | 更新日期: 2023-09-27 17:58:38

class Foo
{
    int Data;
    public Foo(int data)
    {
        Data = data;
    }
    public void Diminish()
    {
        this.Data--;
    }
}
Foo Foo1 = new Foo(5);
Foo1.Diminish();

当数据在Foo10时,有什么方法可以删除Foo1吗?

(释放该实例使用的内存(

如何删除该实例中的类的实例

对象永远不会决定何时"删除"或垃圾回收自身。它无法知道还有什么引用它。当没有对对象的引用时,它会被垃圾回收。

在问题中描述的场景中 - 假设您有一个List<Foo>(),然后根据自己的内部逻辑自发决定它不应该再存在Foo的一个实例?我不知道那会是什么样子 - 所有对它的引用突然变得空?

如果这是可能的,它造成的缺陷将超出所有凡人的理解。当两个线程由于不正确/不存在的锁定而修改相同的对象或属性时,我们会遇到足够的麻烦,因此从一个线程的角度来看,某些内容在不应该更改时发生了变化。

但是,即使在单线程应用程序中,这也会产生类似的方案。

var myFoo = new Foo(1);
myFoo.Diminish();
var x = myFoo.Data; // Null reference exception! WTH - it nullified itself!

OOP 的一个基本概念是类不需要过多地了解其他类的内部状态。但是现在你需要"知道"一个类可能会突然选择退出并跳下悬崖进入 GC,并不断对已经不为 null 的对象进行 null 检查。

这是一件非常好的事情,这是不可能的。

正如一些注释和至少一个答案所解释的那样,.NET 程序中的正常引用正是使该对象保持活动状态的原因。不可能以您似乎的意思显式"删除"对象。

只要对象是"可访问的",它就会保持活动状态(即可以从"rooted"引用开始并找到对该对象的引用(。一旦它不再可访问(即使存在对该对象的引用,只要无法从根引用访问该引用,也可能发生这种情况......例如,两个对象之间的循环引用不会阻止这两个对象的垃圾回收,只要对每个对象的唯一引用来自另一个(。

所有这些都在其他地方提供的文档参考中详细讨论。

现在,综

上所述,根据您实际尝试执行的操作,您可能会发现WeakReference<T>类正是您所需要的。此类提供了一种引用对象而不阻止它们被垃圾回收的方法。您可以将其与引用计数和对象存储库相结合,以维护非弱引用,以保持对象处于活动状态以产生所需的结果。

例如:

class RefCounted
{
    private static readonly HashSet<RefCounted> _alive = new HashSet<RefCounted>();
    private int _referenceCount;
    public RefCounted()
    {
        AddRef();
    }
    public AddRef()
    {
        if (_referenceCount == 0)
        {
            // the collection ensures a strong reference to the object, to prevent
            // the object from being garbage-collected even if the only other
            // references are weak references.
            _alive.Add(this);
        }
        _referenceCount++;
    }
    public Release()
    {
        if (--_referenceCount)
        {
            // no longer need to force the object to stay alive; if the only remaining
            // references to the object are weak references, then the garbage
            // collector may collect the object.
            _alive.Remove(this);
        }
    }
}

然后你可以像这样使用它:

WeakReference<RefCounted> o = new WeakReference<RefCounted>(new RefCounted());
RefCounted r;
if (o.TryGetTarget(out r))
{
    // do stuff with r
    // done with the object? Then call:
    r.Release();
}

重要的是要注意,这并不完全是您想要的。以上仍然不能让你确定性地控制对象的实际垃圾回收。此外,一旦您将弱引用的目标检索到例如局部变量中,您现在在该局部变量的生命周期内(即直到使用该变量的最后一点(持有对该对象的强引用,并且该对象在该生命周期内无法收集,即使引用计数变为 0(尽管此时该对象当然会在该变量不再存在后被收集或可访问(。

但是,如果您确实需要使用某种类型的引用计数来跟踪并以某种方式控制对象的生存期,那么以上就是您的操作方法。你必须存储WeakReference<T>对象而不是直接引用T,在代码中每个需要它的地方检索目标引用。


当然,仍然存在一个问题,即您为什么认为需要引用计数。即使需要引用计数,为什么引用计数要与对象的生存期直接相关?你的问题没有解释这些方面,所以我不能直接解决它们。我要说的是,在 .NET 程序中有效管理托管对象根本不需要引用计数。只要您不主动干扰对托管对象的引用的维护和使用,.NET 垃圾回收系统在处理对象的生存期方面将比您或我做得更好。

只要任何一段代码引用对象实例,它就会保持"活动"状态。所以,这是你无法从类中真正控制的东西。

来自 MSDN:

.NET Framework 的垃圾回收器管理应用程序的内存分配和释放。每次创建新对象时,公共语言运行库都会从托管堆中为该对象分配内存。只要托管堆中的地址空间可用,运行时就会继续为新对象分配空间。但是,内存不是无限的。最终,垃圾回收器必须执行收集才能释放一些内存。垃圾回收器的优化引擎根据所做的分配确定执行回收的最佳时间。当垃圾回收器执行收集时,它会检查托管堆中不再被应用程序使用的对象,并执行必要的操作来回收其内存。

因此,垃圾回收器将负责在对象超出范围时释放对象,除非您需要释放一些昂贵的(内存消耗(资源。您可以将实例的引用设置为 null,这将终止对象,除非有对该对象的其他引用:

Foo Foo1 = new Foo(5);
Foo1.Diminish();
if(Foo1.Data == 0)
{
    Foo1 = null;
}

C#是一种托管语言,你不能"删除"任何内容,一旦无法再引用某些内容,值清理将由垃圾回收器处理。

在某些极端情况下,您需要处理清理,或者更加了解如何处理创建:

  • 实现IDisposable接口的类的实例应通过调用 Dispose() 方法或包装在 using 语句中来释放
  • 非托管资源包装器(如IntPtr(可能需要使用 Marshal.FreeHGlobal(IntPtr)Marshal.FreeCoTaskMem(IntPtr) 进行清理,如果需要管理它们并且要调用非托管代码
  • 静态(可能长期存在(值永远不会不可引用,除非您主动设置变量以null或从集合中删除项目