[closed][c#]деструктор не вызывается

Lizabeth

есть массив объектов
b[i]=new clients(ref insur_comp.realprod[i%3]);

я удаляю один из них
b[5]=null;
watch показывает, что пятая строка очищается. но деструктор так и не вызывается.даже при окончании всей проги ниодного деструктора не вызывается

public class clients
{
~clients{Console.WriteLine("клиент удален.");}
}

Lizabeth

на сколько я понял,в c# команды delete нет?

kruzer25

Насколько я понял, в c# ещё и сборки мусора нет?

Lizabeth

что бы ни значал твой вопрос,меня интересует одно:как заставить вызываться деструктор

Lizabeth

Насколько я понял, в c# ещё и сборки мусора нет?
MSDN: C# Programmer's Reference:
The programmer has no control on when the destructor is called because this is determined by the garbage collector.

pitrik2

я удаляю один из них
b[5]=null;
вранье!
ты не удаляешь его, а говоришь сборщику мусора что он тебе не нужен
когда-нибудь, а может и вообще никогда - это на усмотрение сборщика мусора
этот объект удалится

Lizabeth

ну и что?и когда коллектор собирается увидеть,что объект удален?

pitrik2

ну и что?и когда коллектор собирается увидеть,что объект удален?
увидит сразу
удалит - неизвестно когда

Lizabeth

ну да, удаляется связь с объектом. и когда же коллектор это увидит?или можно как-то иначе сделать?

pitrik2

или можно как-то иначе сделать?
смотря что ты хочешь сделать
совет: представь что в C# ВООБЩЕ нету деструкторов
или даже еще круче: ВООБЩЕ нету понятия удаления объектов
теперь имея это ввиду, попробуй переписать свою прогу

Lizabeth

сказка.....
ну ладно,мне просто хотелось удостовериться,что объект удален. нет так нет
спасибо большое!

kruzer25

Но, тем не менее, когда-то объект ведь должен удалиться?

Lizabeth

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

Dasar

> Но, тем не менее, когда-то объект ведь должен удалиться?
на мелкой проге, он может вообще при выходе только прибьется

kruzer25

Но тем не менее, прибъётся - и должен будет в консоль эту отладочную строчку вывести?

Dasar

при выходе - деструкторы не вызываются

vall

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

Lizabeth

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

grek72

сборку мусора Дж. Рихтер подробно описывал вроде

agaaaa

хм... откуда такая информация? это странно...

prosh123

Можно насильственно заставить очистить и убить все нулевые ссылки командой
GC.Collect

FRider

GC.Collect
И даже это может не помочь и это будет в порядке вещей.
Тем, кто пишет на .нет нужно забыть о "гарантированном" освобождении памяти.
Автор треда очень невнимательно ознакомился с концепцией разработки под .нет

kruzer25

при выходе - деструкторы не вызываются
Хренасе.
Это же жопа!
Я никогда не слышал рекомендаций типа "не помещайте в деструкторы логику, вообще ничего там не делайет, кроме освобождения памяти!"
В чём тогда вообще смысл этих деструкторов?
ЗЫ: А вообще, в чём проблема в managed коде отслежывать количество ссылок на объект, при удалении его из очередной области видимости уменьшать счётчик на 1, и вызывать деструктор, когда счётчик станет 0? Так, вроде, и быстро будет (не надо с какой-то периодичностью вызывать сборщик мусора, который будет как-то хитро искать объекты, которые можно удалить и более понятно?
Или это чревато сильными глюками?

kokoc88

Или это чревато сильными глюками?
Последовательность уничтожения объектов неопределена.

kruzer25

Почему неопределена?
При каждой атомарной команде счётчик уменьшается только для одного объекта, не более, чем на 1; если счётчик стал 0 - вызываем деструктор объекта, который сам удаляет своё содержимое (там всё так же, с атомарными командами); после деструктора в произвольном порядке уменьшаем на 1 счётчики всех выживших после деструктора членов объекта...
UPD: С выходом из функции немного сложнее, но там тоже можно, в общем-то, в рпоизвольном порядке уменьшать на 1 счётчики для всех объектов, на которые были локальные ссылки.
PS: Хотя да, будет косяк с рекурсивными ссылками - для них уже, наверное, всё-таки придётся запускать сборщик мусора. Но, возможно, обычно их не настолько много, и можно их удалить только один раз - действительно, уже при выходе; и обойтись без сборщика мусора...

kokoc88

Почему неопределена?
Ты сам в своём посте описал часть проблем. В языке программирования должна быть чёткая спецификация на то, что происходит в том или ином случае. Так же нужно изучить, как работают сборщики мусора - и всё сразу станет понятно.

kruzer25

Ты сам в своём посте описал часть проблем
Всё-таки, единственная проблема, которую я вижу - это рекурсивные ссылки...

FRider

не помещайте в деструкторы логику, вообще ничего там не делайет, кроме освобождения памяти!
ну здрастье приехали...

pitrik2

тогда зачем писать на C#?
ты фактически реализуешь свой сборщик мусора
люди на С++ так и делают
C# же предоставляет уже готовый сборщик, почему его не юзать?
или ты думаешь что твой сборщик будет быстрее работать? тогда пиши на сях

kruzer25

ты фактически реализуешь свой сборщик мусора
Где я это говорил?

kruzer25

ну здрастье приехали...
Но ведь так и получается - деструктор может вызваться, а может и не вызваться... зачем они вообще тогда нужны?

FRider

зачем они вообще тогда нужны?
Для того, чтобы дать хоть какуюто возможность освободить неуправляемые ресурсы(при закрытии приложения, они освобождаются кстати и так).
Не, ну реально, неужели так сложно прочитать базовую литературу?

kruzer25

То есть, деструкторы в C# нужны только для того, чтобы, если сборщик мусора заметил твой объект - он вместе с объектом удалил ещё и кое-какие ресурсы, если объект ему об этом скажет?
А если я хочу, например, в деструктор моего объекта "подключение к бд" поместить запрос "commit", то, может быть, закоммитится, а может быть, и нет?

Dasar

> А если я хочу, например, в деструктор моего объекта "подключение к бд" поместить запрос "commit", то, может быть, закоммитится, а может быть, и нет?
так не надо такую логику помещать в деструктор.
эту логику надо помещать в Dispose.

kruzer25

А можно поподробнее, в вики про него ничего не написано...
Всё-таки, непонятно, зачем изобретать велосипед, и почему бы не поместить такую логику в деструктор (точно так же, как логика инициализации помещается в конструктор).
Чем было бы плохо, если бы деструкторы вызывались для всех объектов, а не так неявно - "если garbage collector твой объект подберёт, деструктор вызовется; а не подберёт - так всю память сами очистим при выходе"?

Dasar

> Всё-таки, непонятно, зачем изобретать велосипед, и почему бы не поместить такую логику в деструктор (точно так же, как логика инициализации помещается в конструктор).
так было правильно в C++, почему ты считаешь, что так делать правильно и в других языках?
в C++ это было лишь потому, что деструкторы вызывались явно.
> Чем было бы плохо, если бы деструкторы вызывались для всех объектов, а не так неявно
любая явность - это приговор для оптимизации
соответственно при явных деструкторах - падает скорость работы приложения.
GC заявляет лишь одно, память больше не ресурс (ресурс - это объект, который требует обязательного своего закрытия/чистки)
соответственно,
GC не является инструментом для работы с ресурсами
ресурсы надо чистить явно, для этого в .net-е существует IDisposable + using

kruzer25

любая явность - это приговор для оптимизации
Я говорю "если удаляете объект класса XXX - выполните для него ещё и такой код; выполните обязательно, даже если это произойдёт при завершении программы". Где тут приговор для оптимизации?
Ты говоришь то же самое, только у тебя для этого надо использовать не один деструктор, а какую-то анальную комбинацию деструктора, Finalizer-а и этого Dispose. Если же никакой хитрый алгоритм уничтожения не нужен - то и утебя, и у меня не будет ни деструктора, ни finalizer-а, ни dispose.
Ещё раз - зачем изобретать велосипед?

Dasar

> Я говорю "если удаляете объект класса XXX - выполните для него ещё и такой код
как только ты такое говоришь, так сразу и начинается:
1. в каком потоке этот код необходимо выполнять?
2. что будет если этот код задумается на пару часов?
3. что должно быть, если этот код кинет исключение?
4. можно ли вот в такой проге Finalizer вызвать раньше, чем закончится Execute?
hint: Execute не использует this, соответственно можно считать, что во время использования Execute - объект a не используется

class A
{
~A{Console.WriteLine("A.~A");
public void Execute
{
Console.WriteLine("A.Execute");
Thread.Sleep(TimeSpan.FromHours(1;
Console.WriteLine("A.Execute");
}
static void Main
{
A a = new A;
a.Execute;
}
}


и т.д.
поэтому и рекомендуется в Finalizer пихать код только в редких случаях

kruzer25

1. в каком потоке этот код необходимо выполнять?
В каком-нибудь там "нулевом".
2. что будет если этот код задумается на пару часов?
Будет думать пару часов.
3. что должно быть, если этот код кинет исключение?
Смерть и предложение послать отчёт об ошибке авторам программы.
hint: Execute не использует this
И?
Хотя он и не использует - ссылка на объект есть там, откуда был вызван Execute.
можно ли вот в такой проге Finalizer вызвать раньше, чем закончится Execute?
Я вот что-то не понял - что такое finalizer и зачем оно нужно, если есть нормальные деструкторы?

Dasar

> В каком-нибудь там "нулевом".
т.е. каждый объект надо писать как многопоточный?
> Будет думать пару часов.
т.е. сборка мусора у нас зависнет на эти пару часов?
> Смерть и предложение послать отчёт об ошибке авторам программы.
ууу... это ты так собираешься писать надежные серверные приложения?
> Хотя он и не использует - ссылка на объект есть там, откуда был вызван Execute.
сразу после начала Execute она помечается, как неиспользуемая.
> Я вот что-то не понял - что такое finalizer и зачем оно нужно, если есть нормальные деструкторы?
Finalizer и деструктор - в .net-е - это синонимы

kruzer25

ууу... это ты так собираешься писать надежные серверные приложения?
Знаешь ли, в надёжном серверном приложении могут и exit написать.
Кинули (или не поймали) exception в деструкторе - ССЗБ.
т.е. каждый объект надо писать как многопоточный?
Я имел в виду, в нулевом потоке приложения.
т.е. сборка мусора у нас зависнет на эти пару часов?
Ну да.
Хотя, как вариант - порождать новый поток. ХЗ, я не специалист в многопоточности.
А что даёт твой Finalizer? Просто, в википедии про него почти ничего не написано.
сразу после начала Execute она помечается, как неиспользуемая.
Как это?
Она должна помечаться как неиспользуемая,Э когда мы напишем a = null, delete a или выйдем из этой функции.
Finalizer и деструктор - в .net-е - это синонимы
То есть, Finalizer тоже вызывается не всегда?

aleks058

В C# нет деструкторов.
Зато есть файналайзеры.
Они применяются для освобождения неуправляемых ресурсов (файлы, сокеты, com-объекты).
Особенности у них такие:
- неизвестно, когда вызовется файналайзер
- неизвестно, в каком порядке вызовутся файналайзеры
- файналайзер может быть вызван даже для объекта, в конструкторе которого полетело исключение, поэтому

class MyClass
{
StreamReader _file;

public MyClass(string fileName)
{
// Если этот вызов завершится неудачно, полетит какое-то исключение
_file = new StreamReader(fileName); }

~MyClass
{
// Не буду писать Dispose для краткости
_file.Close; // Тут получишь NullReferenceException уже в потоке файналайзеров
}
}

- если какой-то файналайзер затупит надолго, другие будут ждать, потому что файналайзеры выполняются в однопоточном режиме.
- файналайзеры гарантированно вызываются при штатном завершении приложения. Но если тут возникнет задержка, файналайзеры в конце очереди не вызовутся вообще.
- и т.д.

Dasar

> Они применяются для освобождения неуправляемых ресурсов (файлы, сокеты, com-объекты).
уточню, неуправляемые ресурсы - это handle-ы + com-объекты, файл и сокет уже являются управляемыми объектами, и их надо грохать из под Dispose-а, но не из под деструктора
> - файналайзеры гарантированно вызываются при штатном завершении приложения. Но если тут возникнет задержка, файналайзеры в конце очереди не вызовутся вообще.
согласен, ранее был не прав

Dasar

> Знаешь ли, в надёжном серверном приложении могут и exit написать.
> Кинули (или не поймали) exception в деструкторе - ССЗБ.
exit можно и запретить делать (для этого тот же CAS существует а вот запретить exception-ы кидать...
> Я имел в виду, в нулевом потоке приложения.
что такое тогда нулевой поток приложения? и в каких потоках остальной код работает?
> Она должна помечаться как неиспользуемая,Э когда мы напишем a = null, delete a или выйдем из этой функции.
это утверждение не очевидное, т.е. непонятно зачем у нас в памяти должны висеть все эти объекты a, b, c, если мы на них больше нигде не ссылаемся...

string a = "1";
string b = a + "1";
string c = b + "1";
string d = c + "1";

> То есть, Finalizer тоже вызывается не всегда?
100% гарантии, что он вызовется - нет

kruzer25

непонятно зачем у нас в памяти должны висеть все эти объекты a, b, c, если мы на них больше нигде не ссылаемся...
.NET настолько интеллектуален, что в момент исполнения какой-то команды он знает, что там впереди до выхода из функции?
Если нет - то никто не узнает, что эти объекты нигде дальше не используются.
100% гарантии, что он вызовется - нет
То есть, опять - коммит может произойти, а может и не произойти; и все такие вещи приходится вызывать вручную (хотя совершенно непонятно, в чём смысл, если можно было бы сделать нормальные деструкторы, и сказать "вот это деструктор, если вы его написали, то он будет вызван, пусть даже мы сейчас точно не можем сказать, когда (хотя можем сказать, что в момент его вызова все члены объекта ещё будут существовать)".

Dasar

сколько повторять, что для 100% гарантии есть using/dispose, а не деструктор

Marinavo_0507

> для 100% гарантии есть using/dispose, а не деструктор
а какого-нибудь аналога shared_ptr нет?
время жизни дескриптора не так уж часто связано с лексическим блоком в коде

aleks058

> уточню, неуправляемые ресурсы - это handle-ы + com-объекты, файл исокет уже являются управляемыми объектами, и их надо грохать из подDispose-а, но не из под деструктора
С первой частью согласен.
А про деструктор - нет.
Есть стандартный Dispose-паттерн. Выглядит он как-то так:

class MyClass : IDisposable
{
public void Dispose
{
Dispose(true);
}

~MyClass
{
Dispose(false);
GC.SuppressFinalize(this);
}

private bool _isDisposed = false;

protected virtual void Dispose(bool userCall)
{
if (!_isDisposed)
{
// Освободить управляемые ресурсы и те, у которых есть управляемая обертка
// _file.Close например

if (userCall)
{
// Освободить неуправляемые ресурсы
// Отдать хэндлы какие-нибудь виндовые, например,
// или Marshal.ReleaseComObject(_comObject);
}

_isDisposed = true;
}
}
}

Меня всегда удивляет, почему в примерах, которые я видел, Dispose(<без параметров>) постоянно пишут потоконебезопасно.
Он же в принципе может быть вызван одновременно из разных потоков?

Dasar

> Есть стандартный Dispose-паттерн. Выглядит он как-то так:
этот пример не правильный
   // _file.Close например
при вызове этого кода из деструктора может оказаться, что file уже прибит GC.
а com-объект утечет, если забудем вызвать Dispose у этого объекта
правильный пример (здесь как раз показано, что managed классы прибиваются только из Dispose, а unmanaged прибивается всегда):

using System;
using System.ComponentModel;

// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.

public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component;
// Track whether Dispose has been called.
private bool disposed = false;

// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}

// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}

// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose;
}

// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
}
disposed = true;
}

// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);

// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
public static void Main
{
// Insert code here to create
// and use the MyResource object.
}
}

> Меня всегда удивляет, почему в примерах, которые я видел, Dispose(<без параметров>) постоянно пишут потоконебезопасно.
эти примеры часто приводятся для контролов/компонентов, а контролы/компоненты выполняются из под sta-потоков,
деструкторы же для объектов из sta-потоков вызываются из под самого sta-потока.

Dasar

> .NET настолько интеллектуален, что в момент исполнения какой-то команды он знает, что там впереди до выхода из функции?
при компиляции метода уже известно после какого момента переменная не используется.

Dasar

> а какого-нибудь аналога shared_ptr нет?
штатного нет, т.к. универсального shared_ptr все равно не существует - основная проблема с циклическими ссылками

kruzer25

А если
string a = "1";
string b = a + "1";
string c = b + "1";
string d = c + "1";
if(a == b) {
printf('%s%s%s%s',a,b,c,d);
}

?

Dasar

> А если
тогда будут все 4 строки висеть в памяти до момента проверки if-а.

Marinavo_0507

основная проблема с циклическими ссылками
ну помнится меня тут убеждали, что такого не бывает
и во многом убедили

Marinavo_0507

> штатного нет,
а нештатный сделать?
там основная задача - автоматически как-то выделять все структуры, которые одним из элементов могут содержать такой указатель, и менять для них логику GC с обычного на подсчёт ссылок
> т.к. универсального shared_ptr все равно не существует
в принципе, может существовать такой GC, который будет сразу же освобождать то, что можно освободить
он будет неэффективен, но если ему придётся иметь дело лишь с небольшой долей объектов, то это нестрашно

Dasar

> ну помнится меня тут убеждали, что такого не бывает
> и во многом убедили
основная проблема с ссылками на родителя и со ссылками на контекст.
какой-нибудь
...item.Delete;
подразумевает, что у этого item-а как минимум есть ссылка на родительскую коллекцию

Marinavo_0507

> основная проблема с ссылками на родителя и со ссылками на контекст
это решается, если уж допускаем разные виды ссылок
> item.Delete
имхо плохой стиль

Dasar

> имхо плохой стиль
иначе получается, что во все функции надо тащить полную иерархию до элемента.
возьмем простейший пример - окна.
если есть вложенность:
mainform->panel->grid->button, то для того, чтобы работать полноценно с button-ом, необходимо в каждый метод передавать:
execute(mainform, panel, grid, button);
без обратных ссылок, как ты собираешься реализовать тот же самый метод ClientPointToScreen (преобразование локальных координат контрола в мировые)?

kruzer25

А как насчёт "слуга моего слуги - не мой слуга"?

Dasar

> А как насчёт "слуга моего слуги - не мой слуга"?
и чем этот принцип в данном случае помогает?

kruzer25

Тем, что вообще-то, при правильном стиле, передавать надо будет только прямого родителя (это к вопросу о стиле)?

Dasar

> Тем, что вообще-то, при правильном стиле, передавать надо будет только прямого родителя (это к вопросу о стиле)?
почему ты считаешь, что этот "правильный" стиль упрощает решение реальных задач?
вот расскажи как ты с этим правильным стилем будешь решать, например, задачу преобразования локальных координат в экранные?
т.е. как будет выглядит сама функция преобразования? и как будет выглядеть ее вызов?

Lizabeth

Автор треда очень невнимательно ознакомился с концепцией разработки под .нет
фишка в том,что я и не знакомился с ней.я знаю только c++(ну типа того,что знаю). заставили писать под c# -вот и задаю разные вопросы,которые для всех знающих хоть что-то об этом языке вызывают бурю эмоций.но ничего, перейдя с windows application на console application, решил несколько проблем.могу похвастаться, прога готова. далеко не без помощи вас, дорогие форумчане!
БОЛЬШОЕ ВАМ ЧЕЛОВЕЧЕСКОЕ СПАСИБО!

Marinavo_0507

без обратных ссылок, как ты собираешься реализовать тот же самый метод ClientPointToScreen (преобразование локальных координат контрола в мировые)?
На практике, думаю, всё равно все хранят список всех элементов в плоской структуре (хеш?) не взирая на иерархию, для эффективности.
Соответственно в функцию передавать, кроме элемента, ещё и мир.
Но я не против таких ссылок, просто придётся делать их другим типом. Точнее, это умные ссылки - другой тип, они даже на GC не должны влиять, только на вызов завершателя.

Lizabeth

ОТДЕЛЬНО ТЕБЕ:
БОЛЬШОЕ ТЕБЕ ЧЕЛОВЕЧЕСКОЕ СПАСИБО!

Dasar

> На практике, думаю, всё равно все хранят список всех элементов в плоской структуре (хеш?) не взирая на иерархию, для эффективности.
так все равно получается, что у нас есть:
1. хэш обратных ссылок
2. обратная ссылка на мир

Marinavo_0507

> 1. хэш обратных ссылок
не обратных, а прямых
> 2. обратная ссылка на мир
не обратная ссылка, а локальная
или глобальная, если мир един

Dasar

На практике, думаю, всё равно все хранят список всех элементов в плоской структуре (хеш?) не взирая на иерархию, для эффективности.
т.е. функция получения детей выглядит так:?

control.GetChilds(world);

Marinavo_0507

Сверху вниз можно спускаться и без контекста. Если конечно тулкит хоть немного похож на традиционные.

aleks058


при вызове этого кода из деструктора может оказаться, что file уже прибит GC.
а com-объект утечет, если забудем вызвать Dispose у этого объекта
да, загнался, признаю.
По памяти писал.

aleks058

при компиляции метода уже известно после какого момента переменная не используется.
Ну и что?
Например:

public static void Main
{
object a = new object;
object b = "Hello, world!";

if (Console.ReadLine == "make reference!")
{
b = a;
}
GC.Collect; // Здесь объект в "a" соберется или не соберется, в зависимости от результата предыдущего if-а

Console.WriteLine(b);
}

Важны не переменные, а объекты, на которые нет ссылок.
А наличие/отсутствие внешних ссылок на граф объектов можно определеить только в рантайме, чем GC и занимается перед сборкой мусора.

Dasar

> да, загнался, признаю.
> По памяти писал
самое интересное, что в msdn-е я нашел оба варианта - и твой (неправильный и свой (правильный)
правда твой урезанный (только в виде пары строчек а свой - полный
похоже, msdn тоже по памяти пишут

Dasar

Важны не переменные, а объекты, на которые нет ссылок.
важно и то, и другое.
есть такое понятие, как gcroot - это те переменные от которых GC начинает считать, что объекты нужны.
в gcroot входит статик-переменные + стековые и локальные переменные кода, который сейчас выполняется (включая все дерево вызовов).
так вот информацию, о том какие локальные переменные в данной точке еще нужны, а какие уже не нужны - подготавливает компилятор.
соответственно в твоем примере при достижении строки GC.Collect компилятор пометит, что переменная b является gcroot-ом, а переменная a - уже нет.

aleks058

Дай, плз, сцылку на неправильный вариант.
Я знаю, что еще в msdn часто косячут с GC.SuppressFinalize;

aleks058

Жаль, что в этом форуме нет кнопочки "Согласен"

kruzer25

для всех знающих хоть что-то об этом языке
Спасибо за комплимент

Dasar

Дай, плз, сцылку на неправильный вариант
ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_vbalr/html/f1ee8458-b156-44e0-9a8a-5dd171648cd8.htm
An overload of the Dispose that frees the class's resources. This method should be called by the Dispose and Finalize methods of the base class:

Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposed Then
If disposing Then
' Insert code to free unmanaged resources.
End If
' Insert code to free shared resources.
End If
Me.disposed = True
End Sub
Оставить комментарий
Имя или ник:
Комментарий: