Время жизни объекта, нативные ресуры, GC и конструкторы
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 21.09.11 12:54
Оценка:
Привет всем.

Вот пример реализации конструктора класса объекта, который управляет ресурсом в виде блока памяти.
// System.Data.OleDb.PropertyIDSet
internal PropertyIDSet(Guid propertySet, int propertyID) : base(PropertyIDSet.PropertyIDSetAndValueSize)
{
    this._count = 1;
    IntPtr intPtr = ADP.IntPtrOffset(this.handle, PropertyIDSet.PropertyIDSetSize);
    Marshal.WriteIntPtr(this.handle, 0, intPtr);
    Marshal.WriteInt32(this.handle, ADP.PtrSize, 1);
    intPtr = ADP.IntPtrOffset(this.handle, ODB.OffsetOf_tagDBPROPIDSET_PropertySet);
    Marshal.StructureToPtr(propertySet, intPtr, false);
    Marshal.WriteInt32(this.handle, PropertyIDSet.PropertyIDSetSize, propertyID);
}

В данном коде интересна последняя строчка. В ней (грубо говоря)
1. читается значение this.handle (это адрес блока памяти) и помещается в стек
2. вызывается Marshal.WriteInt32.

Формально, если этот конструктор вызывается из кода вида
new PropertyIDSet(new Guid(),1);

То сборщик мусора между п1 и п2 вполне может решить, что конструируемый объект (this) больше не достижим, и инициирует его освобождение (то есть — освобождение блока памяти ресурса). И, в результате, Marshal.WriteInt32 тупо испортит память?

Или то, что new (формально) передает this в конструктор, а потом возвращает его (this) вызывающей стороне, удерживает GC от уничтожения этого объекта?

Эта мысль пришла в голову во время написания этого сообщения

----
Вообщем — может ли GC изничтожить освободить объект, конструктор которого еще не закончил работу?

тут я немного подумал еще, и понял — это же можно проверить самому

Смелый эксперимент (потомка советского инженера) показывает — да запросто
  Скрытый текст
using System;

class A
{
  static void RunGC()
  {
   // Производим сборку мусора.
   Console.WriteLine("Run GC");

   GC.Collect();
   GC.WaitForPendingFinalizers();
  }

  public A()
  {
   Console.WriteLine("A - in");

   RunGC();

   Console.WriteLine("A - out");
  }//if

  ~A() { Console.WriteLine("~A();"); }

  static void Main()
  {
   Console.WriteLine("Main - in");

   new A();
   
   Console.WriteLine("Main - point #1");

   RunGC();

   Console.WriteLine("Main - exit");
  }//Main
}//class A

Main - in
A - in
Run GC
~A();
A - out
Main - point #1
Run GC
Main - exit
Для продолжения нажмите любую клавишу . . .
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.