2009-11-30 5 views
1

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

Как так:

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 и deconstructors в настоящее время.

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

Еще раз спасибо всем, кто помог!

+0

Можете ли вы предоставить наименьший набор кодов, воспроизводящих поведение? – jason

+0

«Разве это может быть связано с тем, как класс Dictionary добавляет новые ссылки?» Маловероятно. Словарь содержит сильные ссылки, которые предотвращают сбор любых ключей или значений до тех пор, пока не будет собрано сам словарь. – itowlson

+0

@Mark: Хорошо, это вздох облегчения.Поведение, которое вы описывали, не должно происходить, ЕСЛИ не было недостатка в вашем коде. Рад, что мы могли бы «помочь». – jason

ответ

0

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

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

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

3

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

+0

Я думаю, что можно с уверенностью предположить (отметьте, пожалуйста, исправьте), что он все еще держит ссылку на свой экземпляр 'A' (« Я НИКОГДА не удаляю их из этого словаря », я предполагаю, что это означает, что словарь и, следовательно, его экземпляр 'A' все еще существует). – jason

+0

Это правильно, я создал Консольные инструкции в Destructor класса A, и он никогда не называется – Mark

1

Я никогда не удалить их из этого словаря, но по какой-то причине, деструктор для класса B вызывается

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

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

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

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

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

Может быть что-то делать с тем, как Словарь класс добавляет новые ссылки?

No.

+0

. Я думал, что это тоже так, поэтому я помещаю инструкции Console в свой деструктор класса A, и он никогда не вызывает вызов вообще. .. – Mark

+0

У вас нет деструктора в вопросе. Если вы это сделаете, многое изменится. Поэтому вам лучше предоставить весь проблемный код. –

-2

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

0

Поэтому у меня есть следующий тип:

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()); } 

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

1

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

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

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

+0

Великий материал Джоэл. Мне интересно, как финализатор, по-видимому, является одним из наименее понятных понятий в .NET. Плюс один. – jason

Смежные вопросы