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

时间:2016-07-26 19:19:08

标签: c#

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

Foo1内的数据为0时,有没有办法删除Foo1

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

5 个答案:

答案 0 :(得分:2)

对象永远不会决定何时“删除”或垃圾收集本身。它无法知道还有什么参考它。当没有任何引用留给对象时,它就会被垃圾收集。

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

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

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

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

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

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

答案 1 :(得分:1)

正如一些评论和至少一个答案所解释的那样,.NET程序中的正常引用正是使该对象保持活力的原因。不可能以您的意思明确地“删除”对象。

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

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

现在,所有这一切,取决于你实际上要做什么,你可能发现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垃圾收集系统就可以更好地处理对象的生命周期。

答案 2 :(得分:0)

来自MSDN:

  

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

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

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

答案 3 :(得分:0)

对象实例将保持&#34; alive&#34;只要任何一段代码引用它。所以,它是你无法在课堂上真正控制的东西。

答案 4 :(得分:0)

C#是一种托管语言,您无法“删除”任何内容,一旦无法再引用某些内容,垃圾收集器将处理清理值。

有些边缘情况需要处理清理,或者更了解处理创建的方式:

  • 实现IDisposable接口的类实例应通过调用Dispose()方法或包含在using语句中来处理
  • 如果您需要管理IntPtrMarshal.FreeHGlobal(IntPtr),并且您正在调用非托管代码,则可能需要使用Marshal.FreeCoTaskMem(IntPtr)清除非托管资源包装器,例如null / LI>
  • 除非您主动将变量设置为1 error prohibited this project from being saved: 或从集合中删除项目,否则静态(可能长寿)值永远不会不可引用