当前位置: 首页 > 知识库问答 >
问题:

如何阻止一个对象(以及它里面的一切)被最终确定?

叶经略
2023-03-14

在我长达两周的寻求解决一个问题的过程中:

    null

有什么方法可以防止对象被最终确定吗?

例如,下面的代码有缺陷,因为终结器错误地表示私有_values对象仍然存在。事实上,它很可能已经在我的领导下完成了:

class Sqm
{
   private List<Value> _values = new List<Value>();

   //finalizer
   public ~Sqm()
   {
       Shutdown();
   }

   protected void Shutdown()
   {
      foreach (var value in _values)  //<-- crash; _values no longer exists
         SaveValueToHardDrive(value); //<-- crash; value no longer exists
   }
}

我需要的是一种方法来告诉垃圾收集器不要最终确定该列表对象或其中的任何对象:

class Sqm
{
   private List<Value> _values = new List<Value>();

   //constructor
   public Sqm()
   {
      GC.LetMeManuallyFinalize(_values);
   }

   //finalizer
   public ~Sqm()
   {
       Shutdown();
       GC.ManuallyFinalize(_values);
   }

   protected void Shutdown()
   {
      foreach (var value in _values) 
         SaveValueToHardDrive(value);
   }
}
  protected void Shutdown()
  {
     foreach (var value in _values) 
        SaveValueToHardDrive(value); //<---crash, contained object already finalized
  }
public void AddSample(String name, Int64 value)
{
    Entry entry = GetEntryByName(name);
    if (entry == null)
    {
       entry = new Entry();
       GC.LetMeManuallyFinalize(entry);
    }

    entry.Count += 1;
    entry.Sum += value;
    entry.Average = entry.Sum / entry.Count;
}

//finalizer
public ~Sqm()
{ 
   foreach (var value in _values)
      GC.ManuallyFinalize(value);

   GC.ManuallyFinalize(_values);      
}

@MatthewWatson有个好主意。我想指出为什么它是错误的是有用的。使用gcalloc.alloc保存对对象的引用。然后在终结器期间使用can访问它:

public Sqm()
{
   private List<Value> _values = new List<Value>();
   private GCHandle _valuesHandle; //handle to keep _values alive

   //constructor
   Sqm()
   {
      //prevent _values from being finalized
      _valuesHandle = GCAlloc.Alloc(_values); 
   }

   //finalizer
   ~Sqm()
   {
      try
      {
         Shutdown(_values); //Safe, right? RIGHT? _values couldn't have been finalized
      } 
      finally
      {
         _valuesHandle.Free();
      }
   }

   private void Shutdown(List<Values> values)
   {
      foreach (var value in values)
      {
         //The list itself might not have been finalized
         //But objects used internally to Microsoft's List<T> class have been finalized
         //and objects in the list itself were already finalized
         SaveValueToHardDrive(value); //<--BAD: values inside list were already finalized
      }
   }
}

注意:由于伪文档化的行为,它也可能失败。从关于Gchandles的真相来看:

当您创建一个新的gchandle时,将在AppDomain的句柄表中创建一个新条目。在释放句柄(通过gchandle.free())或卸载AppDomain之前,该条目一直保持不变。

棘手的部分是我不拥有的班级的内部私人成员;即使一个仍然被gcalloc引用的对象仍然会有它所依赖的对象在背后完成。

public static Foo
{
   public static Sqm = new Sqm();
}

Foo.Sqm.AddSample("QueryCustomerInfo", stopwatch.TotalMicroseconds);

共有1个答案

索瀚海
2023-03-14

这是一个非常糟糕的做法,在完成任何长期的操作,如输入输出,无论如何。您应该考虑将对象的_values列表存储在静态列表中--这将防止值被破坏。当对象最终确定时,可以将对内部列表的引用保存在另一个静态列表中,定期检查该列表。当它包含对列表的引用时,这将意味着您的对象被析构,它包含的值应该被保存。

class Sqm
{
  private static List<List<Value>> = _lists = new List<List<Value>>();
  private static List<List<Value>> = _finalizationQueue = new List<List<Value>>();
  private List<Value> _values = new List<Value>();
  Sqm() { _lists.Add(_values); }
  ~Sqm() { _finalizationQueue.Add(_values); }
  public static void CheckAndSave()
  {
    foreach(var list in _finalizationQueue)
      SaveValues(list);
  }
}

如果域可能在你不想关机的时候关机,你唯一的方法是将值存储在另一个域中。

 类似资料:
  • 问题内容: 我在多对一元素中声明的域对象上有一个属性。此属性的基本语法如下所示: 现在,我们的想法是让Hibernate不急于获取此属性。它可能为null,因此设置了未找到的忽略。 但是,Hibernate在加载包含此关联的类时,会在加载父类时自行加载实际的类(甚至不是代理)实例。由于某些属性的大小超过1MB,因此它们会占用大量堆空间。 但是,如果将not-found设置为exception(或默

  • 问题内容: 我看到lambda的类是,但是我认为对于代理类而言可能同样如此。 当然,我可以检查一下并应用于类名。 但是我想知道是否有一个更优雅,更强大的选项来确定给定的对象是否为lambda。 问题答案: 设计上没有官方的方法可以做到这一点。Lambda是语言的一部分;并通过功能接口集成到类型系统中。无需区分以lambda,命名类或内部类开头的生命,它们都是Runnable。如果您认为必须拆开类文

  • 在 中,尝试捕获最终阻止的工作原理是什么? 所以如果有例外,我知道它会跳到捕获块,然后跳到最后的块。 但是如果没有错误,catch块不会运行,但是finally块会运行吗?

  • 以下是问题陈述: 编写一个java程序,使用线程计算前25个素数,并计算前50个斐波那契数。将计算斐波那契数的线程的优先级设置为8,将另一个设置为5。在计算了30个斐波那契数之后,让这个线程进入睡眠状态,开始计算素数。计算完25个素数后,继续斐波那契数计算。 我的代码: 我本以为当斐波那契线停止时,其余的素数会被打印出来,但那没有发生,这背后的原因可能是什么?

  • 问题内容: 我有一个进程A,它在内存中包含一个带有一组记录(recordA,recordB等的表)的表。 现在,此过程可以启动许多影响记录的线程,有时我们可以有2个线程尝试访问同一记录- 必须拒绝这种情况。具体来说,如果一条记录被一个线程锁定,我希望另一个线程中止(我不想阻止或等待)。 目前,我正在执行以下操作: 但这引起了我的问题…因为Process1在执行操作时,如果Process2进入其中,

  • 问题内容: Ajax使用回调,因为它是同步的。 我希望对远程URL块的调用直到出现一些答案为止 ,就像在Ajax中一样,但是没有异步部分,或者我要说要进行JAX调用。 是否有任何技术可以使以下事情发生(使用JQuery)(…使用JQuery或其他解决方案): 我只是想知道-想学习。 实际上,有时会阻塞直到回复合适为止。我并不是说要浏览器阻止,而只是脚本运行时。 问题答案: 您可以在使用jQuery