Почему моего Деструктора вызывают? - PullRequest
1 голос
/ 30 ноября 2009

У меня есть несколько классов, которые содержат ссылки на другие классы через члены экземпляра IDictionary.

Вроде так:

class A
{
  private readonly Dictionary<int, B> _particles = new Dictionary<int, B>();
  public void CreateNewB(int someInt)
   {
     var b = new B();
     if (!_particles.ContainsKey(someInt)
         _particles.Add(someInt, b);
   }
}

так что это настройка, и я НИКОГДА не удаляю их из этого словаря, но по какой-то причине деструктор для класса B время от времени вызывается при запуске GC, и я не понимаю, почему.

Может быть, это связано с тем, как класс Dictionary добавляет новые ссылки?

FIXED :

Хорошо, спасибо всем за ваши ответы, я, безусловно, теперь хорошо разбираюсь в GC и деконструкторах.

Но проблема была моей, я добавлял someInt только в том случае, если он еще не существовал и из-за некорректной бизнес-логики, someInt всегда был 1, поэтому первый раз через него работал, и деконструкторы не вызывали. Но во второй раз экземпляр "b" просто не был добавлен в список и был очищен при запуске GC.

Еще раз спасибо всем, кто выручил!

Ответы [ 6 ]

3 голосов
/ 30 ноября 2009

Ваш класс B будет GC, если ссылка на класс A мертва

1 голос
/ 30 ноября 2009

Похоже, вы делаете что-то очень неправильно. В управляемой среде сохранение такой ссылки, которая будет существовать вечно, равнозначно утечке памяти, если вы действительно не хотите хранить эти объекты.

Еще одна вещь, которую следует помнить, это то, что в C # нет такого понятия, как деструктор. У вас есть финализаторы , которые отличаются. В управляемом коде редко когда вам вообще нужно писать финализатор. Единственная веская причина для этого - когда вы реализуете IDisposable для типа, чтобы обернуть неуправляемый ресурс , который еще не покрыт финализатором .

Например, многие люди создают тип, который реализует IDisposable и оборачивает SqlConnection как часть своего уровня доступа к данным. Таким образом они могут обернуть экземпляры типа в использование блоков и убедиться, что все создаваемые ими SqlConnections расположены правильно. Но этот тип не нуждается в финализаторе, потому что базовое соединение с базой данных уже покрыто финализатором в самом классе SqlConnection. Не нужно беспокоиться о неуправляемом типе new , а только о типе SqlConnection. Но если бы вы создавали совершенно новый механизм базы данных и внедряли для него новый поставщик данных .Net, вы бы хотели создать финализатор для вашего соединения.

1 голос
/ 30 ноября 2009

Я НИКОГДА не удаляю их из этого словарь, но по какой-то причине деструктор для класса B называется

Деструктор в .NET - это не то же самое, что деструктор в C ++ (неуправляемый).
Деструктор вызывает Завершить метод автоматически.

Вот некоторые характеристики деструктора :

  • Деструкторы не могут быть определены в структурах. Они используются только с классами.
  • У класса может быть только один деструктор.
  • Деструкторы не могут быть унаследованы или перегружены.
  • Деструкторы нельзя назвать . Они запускаются автоматически .
  • Деструктор не принимает модификаторы и не имеет параметров.

Итак, что происходит в вашем случае, это (в двух словах):

  1. Класс А - сбор мусора.
  2. В результате в поле 1: _particles получим GC-d.
  3. В результате 2: записи в словаре стали некорневыми (доступно для сборки мусора).
  4. В результате 3: записи в Словаре (экземпляры класса B) имеют GC-d.

Может быть, это связано с тем, как класс Dictionary добавляет новые ссылки?

номер

0 голосов
/ 10 декабря 2009

Хорошо, спасибо всем за ваши ответы, я, безусловно, теперь хорошо разбираюсь в GC и деконструкторах.

Но проблема была моей, я добавлял someInt только в том случае, если он еще не существовал, и из-за некорректной бизнес-логики someInt всегда был 1, поэтому первый раз, когда он работал, и деконструкторы не вызывались. Но во второй раз экземпляр "b" просто не был добавлен в список и был очищен при запуске GC.

Я отвечаю на это просто, чтобы закрыть его:)

0 голосов
/ 30 ноября 2009

Итак, у меня есть следующий тип:

type k {
public k() { Console.WriteLine("Hi, I'm a new K!"); }
public ~k() { Console.WriteLine("I'm a dying K!"); }
}

И небольшой фрагмент кода:

Dictionary<int, k> ks = new Dictionary<int, k);
for(int i=0;i<10;i++) { ks.add(i, new k()); }

и вы видите, что ~ k () вызывается в одной точке? Это происходит?

0 голосов
/ 30 ноября 2009

Я бы поставил свои деньги на класс B, созданный в другом месте. Если это консольное приложение, выведите что-нибудь в B конструктор и финализатор. Убедитесь, что количество экземпляров соответствует ожидаемому.

...