Re[21]: Правила использования финалайзеров [blog]
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.01.06 11:47
Оценка:
Здравствуйте, TK, Вы писали:

TK>Тут сразу вопрос. А это поле вообще в базовой реализации нужно?

См. базовую реализацию. Вкратце:
1. Нужно корректно обрабатывать повторный вызов Dispose().
2. Нужно кидать исключение ObjectDisposedException во всех остальных методах после Dispose.

TK>т.е. порядок вызова DisposeUnmanaged / DisposeManaged не специфицирован?

TK>рассмотрим ситуацию. есть объект под названием Dialogue который
TK>инкапсулирует в себе некий диалог работы с каналом (unmanaged ресурс). При
TK>вызове Dispose нам надо корректно завершить диалог (сказать что я
TK>пользователь (информация о пользователе это managed ресурс) такой-то работу
TK>завершаю). Соответственно вопрос: как надежно завершить работу в ситуации
TK>когда порядок вызовов DisposeManaged / DisposeUnmanaged не специфицирован? В
TK>DisposeUnmanaged этого по идее сделать нельзя т.к. managed ресурсы уже могут
TK>быть недоступны. Как это сделать из DisposeManaged тоже не ясно т.к.
TK>реализация может вызвать DisposeUnmanaged раньше. Можешь как-то прояснить
TK>данный аспект в своем описании?
Могу. Надо заранее скопировать информацию о пользователе в ресурс, который не будет отпущен в DisposeManaged(). Я приводил пример для хэндла окна в ответе на вопрос Мики.


TK>Ну ок. Уже второй день пошел как мы это обсуждаем. Можно зафиксировать

TK>какое-то решение?
Пока нет.

TK>a. Ключевое слово это ПУЛ ОБЪЕКТОВ. Есть объекты безконтрольное

TK>создание/уничтожение которых является достаточно накладной операцией.
TK>Поэтому, в некоторых случаях, имеет смысл организовать пул подобных
TK>объектов. При этом, для реализации такого пула задействовать какие либо
TK>unmanaged ресурсы вовсе не обязательно.
TK>б. Если ты не понял код, то давай его перепишем более понятно:
Давай.
Вот пример использования:
public static void Main()
{
  using (SomeManagedResource resource1 = new SomeManagedResource())
    {
      resource1 = new SomeManagedResource();
    }
}

Внимание, вопрос: сколько памяти осталось занято при выходе из Main()?
Ладно, это была шутка в сторону. Понятно, что вместо единственного статического поля будет некий список "занятых" и "свободных", и нужно вовремя перекладывать из одного списка в другой. Ок, я понял, в чем проблема. Получается, что у нас есть объекты, которые перекрывают Finalize (и их в финалайзере трогать нельзя и не надо), и объекты, которые его не перекрывают. Значит, нужно провести разделение не по Managed/Unmanaged, а по Finalizable/NonFinalizable:

public class BaseResource : IDisposable
{
  private bool _disposed = false;
    protected bool IsDisposed { return _disposed;}
    
    public void Dispose()
    {
      if (_disposed)
            return;
      DisposeFinalizable();
        DisposeNonFinalizable();
        GC.SuppressFinalize(this);
        _disposed = true;
    }
    
    ~BaseResource()
    {
      DisposeNonFinalizable();
    }
    
    protected void DisposeFinalizable() {}
    protected void DisposeNonFinalizable() {}
}


Вот мы наследуемся для реализации твоего примера:

class SomeManagedResource : BaseResource
{
  byte[] _managedResource;
  static byte[] _cache;

  public SomeManagedResource()
  {
    _managedResource = ManagedAllocate();
  }

  override protected void DisposeNonFinalizable()
    {
    ManagedRelease(_managedResource);
        base.DisposeNonFinalizable();
  }
  
    ~SomeManagedResource()
    {
      Debug.Trace("Warning! Instance of SomeManagedResource has not been properly disposed. This leads to an ineffective pool usage!");
    }
  static byte[] ManagedAllocate()
  {
    byte[] resource;
    if (_cache == null)
    {
      resource = new byte[VERY_BIG_ARRAY];
    }
    else
    {
      resource = _cache;
      _cache = null;
    }

    return resource;
  }

  static void ManagedRelease(byte[] resource)
  {
    _cache = resource;
  }
}

Что еще я упустил?
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Правила использования финалайзеров [blog]
От: Аноним  
Дата: 22.01.06 18:24
Оценка: 42 (2)
Переписка из блога.

mihailik >>>>Многие наши программисты предпочитают что-то слащаво-подростковое, например Рихтера. Классный дядька Рихтер, успешный. Но есть у него много методических провалов.

Gollum >>Ну и "борюсь с Рихтером" — это немного смешно.


Согласен, звучит самоутверждающе. Но не будем делать скорополительных выводов, а лучше посмотрим, возможно, для этого действительно есть определенные основания... Дабы исключить искажение смыла переводчиками (а ручаться можно только за себя), я взял и перечитал английское издание книги Applied Microsoft .NET Framework Programming. Вот то, что я понял, и что мне запомнилось.:

Каждый объект, который работает с неуправляемыми ресурсами (например, с файлами или сокетами), должен поддерживать финализацию (finalization). Финализация позволяет ресурсу прибрать за собой во время сборки мусора. Если объект содержит метод Finalize, то он вызывается сборщиком мусора. Если тип, который работает с неуправляемыми ресурсами, не реализует метод Finalize, то это приведет к утечкам памяти. Ресурсы не будут освобождены покуда не завершится поток, их использовавший.

Переписка из блога.

>>Финализатор имеет смысл только если непосредственно ваш класс хранит в себе Handle внешнего ресурса (за редчайшим исключением).

Очевидно, что именно это и говорит нам Рихтер. Процитирую свой перевод: "Каждый объект, который работает с неуправляемыми ресурсами [skip], должен поддерживать финализацию [skip]." У меня нету сейчас под рукой русского издания, но в этом месте если и возникает разночтение, то только по вине этого самого русского издания. В английском варианте лично для меня тут все достаточно прозрачно.

Тут, между прочим, даже сам Рихтер оговаривается по поводу метода Finalize(), мол, девелоперы не тем боком этот метод юзают, поэтому команда разработчиков компилятора языка C# подумала-подумала, и сделала потенциально опасный код вне закона. Вопрос: это защита от дурака, или от Рихтера? Причем, Рихтер опять же оговаривается, что, в общем-то зря они синтаксис деструктора C# слизали с С++, ведь это только вгоняет сишников в ступор. Опять предупреждение, и не от кого бы то ни было, а от самого Рихтера. А ученики, похоже, просто прохлопали ушами этот момент. Читаем дальше.


Если вы знакомы с С++, то сразу заметите, что синтаксис деструктора (этот метод так и называется в спецификации) совпадает с таковым в С++. Тем не менее, Finalize работает совсем не так, как деструктор в С++. ПРИ НАПИСАНИИ СВОЕГО ТИПА ЛУЧШЕ ВОЗДЕРЖАТЬСЯ ОТ FINALIZE.

Дальше можно уже и не комментировать (но я на этом месте не остановился). Я примерил на себя костюм "разрушителей мифов" с канала Discovery, и судя по всему у меня это неплохо получилось. Ну что, миф разрушен?


В _очередной_ раз видим необоснованный выпад, и кстати, не только в сторону Джеффри Рихтера...


Переписка из блога.

>>Они похожи на деструкторы C++
>>— в результате, программисты пишут и думают себе что-то одно, а получается ОЧЕНЬ другое

Я не знаю, о чем думают программисты, когда пишут свой код, но явно не о Рихтере... И приведенный выше фрагмент в моей интерпретации это полностью доказывает.

>>Они вызываются в нефиксированный момент времени
>>— при отладке в условиях A мы видим одно поведение, а при реальной работе в условиях B имеем совсем другое

Именно об этом нам и пишет Рихтер. Кратко но _доходчиво_ разъясняя технические аспекты. Вот этот отрывок (это мой литературный перевод, можете cверить с "настоящим" русским изданием, вполне возможно, там содержатся ошибки, которые и ведут к оказиям):

"
Примечание.
В таблице 19-1 обратите внимание, что на аргумент arg1 нашего метода больше никто не ссылается после инструкций процессора со смещением 0x00000020. Это значит, что объект arg1 помечается как "пригодный для сборки в любое время" после выполнения этих инструкций (предполагается, что в приложении больше нет корневых элементов, которые ссылаются на этот объект). Другими словами, как только объект становится недостижимым [чтобы понять смысл этой фразы, нужно читнуть пару абзацев выше, но эти потуги я уже возложу на плечи наших "учеников"], он превращается в кандидата на сборку, поэтому не гарантируется, что объекты будут жить на протяжении всего времени выполнения метода.
[Дальше пошло самое вкусное.]
Одако, когда приложение выполняется через отладчик, или когда сборка помечена атрибутом System.Diagnostics.DebuggableAttribute с параметром isJITOptimizerDisabled выставленным в true, компилятор JIT продлевает время жизни всех переменных (будь то типы, передающиеся по значению или по ссылке) до окончания их области видимости, что в большинстве случаев означает конец самого метода. (Между прочим, компилятор C#, при использовании ключа /debug в командной строке, помечает сборку атрибутом DebuggerAttribute, устанавливая параметр isJITOptimizerDisabled в true.) Это расширение предотвращает сборщика мусора от сборки ссылочных типов во время выполнения кода в данной области видимости, что полезно при отладке. Было бы совсем неуместно, если бы вы вызвали метод объекта, получили неправильный результат, а затем не смогли бы даже взглянуть на этот объект!
"

Рихтер сказал один в один по писаному... Или наоборот.


P.S. Рихтер, как известно, на короткой ноге с Microsoft. И я очень сильно сомневаюсь, что кто-то намного лучше самих майкрософтовцев знает, как пользоваться их продуктами. Поэтому бороться если и надо, то не с Рихтером, а с гореучениками, которые не в состоянии уловить мысль человека до конца. Повышать, так сказать, уровень базовых знаний (и в руки Рихтера не давать!). А то человек оперирует таким понятиями, как "функция memcpy", "регистр процессора", хотя для многих "начинающих" это звучит как заклинание. Тогда о каком чтении Рихтера может идти речь? Нужно брать что-то более научно-популярное... Хотя мне кажется, что если читатель толковый, то, дочитав до незнакомого слова, полезет в нет и разберется, что к чему. Это даже способствует повышению уровня своего развития. И не только в сторону освоения .NET. Так что IMHO рано-то Рихтера на свалку истории списывать... Превзойти своего учителя это похвально, вот только не нужно унижать его талант.

Alexander__S >>Финлазиторы плохи, спору нет. Но за все надо платить, в том числе и за GC.

Они не плохи. Просто ко всему нужно подходить с головой. Сначала работает голова, и только потом руки. Тогда все будет путем.

[[url=http://www.gotdotnet.ru/DotNet/FAQ/OfflineFAQ/236958.aspx]Offline FAQ[/url]] [1.01]
2 min @ 56.6 kbps


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[4]: Правила использования финалайзеров [blog]
От: vdimas Россия  
Дата: 27.01.06 12:00
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Вообще, я до сих пор не могу понять этих приплясываний с bool параметром.

S>почему нельзя сделать вот так:

Потому как доступ к полу disposed в этом случае следовало бы сделать блокируемым. Я понимаю, что вряд ли у кого-то получится явно задиспозить из другого потока в момент финализации, но мало-ли что...

Булевская локальная переменная — вполне себе выдержана в духе обычного локального контекста для конкурирующих потоков.

На самом деле можно вводить disposed для unmanaged-ресурсов как дополнение к булевскому флагу + блокировки, если это критично для используемых unmanaged ресурсов, ибо никто не застрахован от многократных конкурирующих Dispose.
Re[5]: Правила использования финалайзеров [blog]
От: Sinclair Россия https://github.com/evilguest/
Дата: 27.01.06 12:35
Оценка:
Здравствуйте, vdimas, Вы писали:
V>Потому как доступ к полу disposed в этом случае следовало бы сделать блокируемым. Я понимаю, что вряд ли у кого-то получится явно задиспозить из другого потока в момент финализации, но мало-ли что...
В момент финализации задиспозить ни из какого потока не "вряд ли", а невозможно. Потому что в очередь финализации попадают только те объекты, на которые уже нет ссылок.
V>Булевская локальная переменная — вполне себе выдержана в духе обычного локального контекста для конкурирующих потоков.
Ты, похоже, смешал в кучу параметр disposing и поле disposed, которые имеют совершенно различный смысл и используются независимо. Перечитай еще раз пример.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Правила использования финалайзеров [blog]
От: Hacker_Delphi Россия  
Дата: 29.01.06 14:03
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Пока что такой нужды не возникло. Я просто предположил, что ты хочешь написать в дебаг не для того, чтобы доказать отсутствие аргумента метода, а для какой-то осмысленной цели. Например, для отлова невызванных Dispose(). В таком случае имеет смысл встроить функционал сразу в базовый класс, чтобы облегчить себе задачу.

Кстати о финализаторах...
Я вот знаю как минимум еще одно место, где они нужны, но при этом нет никакого IDisposable, ибо нету никаких Unmanaged ресурсов
Например, есть у нас Cache, в котором висят WeakReference'ы объектов.
При финализации надо бы эти референсы из Cache вычистить...
Единственный способ — запихать код удаления в финализатор.
Способ с проверкой WeakReference.IsAlive тоже используется — как ни странно, периодически попадаются моменты, когда WeakReference уже "мертв", а финализатор еще не был вызван...
Вот в таком случае нужен финализатор и никуда не сдался IDisposable.
А насчет MS паттерна Disposable(bool), используемого в System.Windows.Forms — он вполне удобен...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Если при компиляции и исполнении вашей программы не происходит ни одной ошибки — это ошибка компилятора :)))
Re[19]: Правила использования финалайзеров [blog]
От: Hacker_Delphi Россия  
Дата: 29.01.06 14:12
Оценка:
Здравствуйте, mihailik, Вы писали:

M>Есть враппер над неуправляемым объектом — у него простое очевидное время жизни. Есть управляемые объекты — у них ещё проще: никакой финализации, только Dispose. Параметры тут вообще не нужны, так как из финализатора вызовов не бывает.

Ну не совсем так... см. Re[18]: Правила использования финалайзеров
Автор: Hacker_Delphi
Дата: 29.01.06
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Если при компиляции и исполнении вашей программы не происходит ни одной ошибки — это ошибка компилятора :)))
Re[19]: Правила использования финалайзеров [blog]
От: mihailik Украина  
Дата: 29.01.06 20:01
Оценка:
H_D>Кстати о финализаторах...
H_D>Я вот знаю как минимум еще одно место, где они нужны, но при этом нет никакого IDisposable, ибо нету никаких Unmanaged ресурсов
H_D>Например, есть у нас Cache, в котором висят WeakReference'ы объектов.

Тут ты ошибся. Даже не в деталях, а в корне ошибся.

Если твой объект "держит" ссылки на другие управляемые объекты, то финализатор вообще не поможет. Когда твой объект будет мусором, то он уже не будет "держать" никого. Есть ли из него ссылки, нет ли — уже никого не волнует. Мёртвые не потеют.

Если же говорить о частностях, то WeakReference не считаются ссылками и не мешают объектам становится мусором.
Re[7]: Правила использования финалайзеров [blog]
От: Alexander__S  
Дата: 29.01.06 20:29
Оценка:
Здравствуйте, eisernWolf, Вы писали:

Офигеть... Только сейчас заметил.

W>[

W>Переписка из блога.

W>mihailik >>>>Многие наши программисты предпочитают что-то слащаво-подростковое, например Рихтера. Классный дядька Рихтер, успешный. Но есть у него много методических провалов.


W>Gollum >>Ну и "борюсь с Рихтером" — это немного смешно.

W>]

Первый вопрос: зачем Вы вывалили это... даже не знаю, как и назвать, в ответ на мой пост? "Программисты, которые предпочитают что-то слащаво-подростковое, например Рихтера", это вроде меня? Если да, то обоснуйте. Что послужило поводом для такого заключения? Может быть, фраза: "Держал в голове рихтеровскую реализацию"?

W>Согласен, звучит самоутверждающе. Но не будем делать скорополительных выводов, а лучше посмотрим, возможно, для этого действительно есть определенные основания... Дабы исключить искажение смыла переводчиками (а ручаться можно только за себя), я взял и перечитал английское издание книги Applied Microsoft .NET Framework Programming. Вот то, что я понял, и что мне запомнилось.:


W>Каждый объект, который работает с неуправляемыми ресурсами (например, с файлами или сокетами), должен поддерживать финализацию (finalization). Финализация позволяет ресурсу прибрать за собой во время сборки мусора. Если объект содержит метод Finalize, то он вызывается сборщиком мусора. Если тип, который работает с неуправляемыми ресурсами, не реализует метод Finalize, то это приведет к утечкам памяти. Ресурсы не будут освобождены покуда не завершится поток, их использовавший.


W>[

W>Переписка из блога.

>>>Финализатор имеет смысл только если непосредственно ваш класс хранит в себе Handle внешнего ресурса (за редчайшим исключением).


W>Очевидно, что именно это и говорит нам Рихтер. Процитирую свой перевод: "Каждый объект, который работает с неуправляемыми ресурсами [skip], должен поддерживать финализацию [skip]." У меня нету сейчас под рукой русского издания, но в этом месте если и возникает разночтение, то только по вине этого самого русского издания. В английском варианте лично для меня тут все достаточно прозрачно.


W>Тут, между прочим, даже сам Рихтер оговаривается по поводу метода Finalize(), мол, девелоперы не тем боком этот метод юзают, поэтому команда разработчиков компилятора языка C# подумала-подумала, и сделала потенциально опасный код вне закона. Вопрос: это защита от дурака, или от Рихтера? Причем, Рихтер опять же оговаривается, что, в общем-то зря они синтаксис деструктора C# слизали с С++, ведь это только вгоняет сишников в ступор. Опять предупреждение, и не от кого бы то ни было, а от самого Рихтера. А ученики, похоже, просто прохлопали ушами этот момент. Читаем дальше.

W>]

W>Если вы знакомы с С++, то сразу заметите, что синтаксис деструктора (этот метод так и называется в спецификации) совпадает с таковым в С++. Тем не менее, Finalize работает совсем не так, как деструктор в С++. ПРИ НАПИСАНИИ СВОЕГО ТИПА ЛУЧШЕ ВОЗДЕРЖАТЬСЯ ОТ FINALIZE.


W>Дальше можно уже и не комментировать (но я на этом месте не остановился). Я примерил на себя костюм "разрушителей мифов" с канала Discovery, и судя по всему у меня это неплохо получилось. Ну что, миф разрушен?


W>[

W>В _очередной_ раз видим необоснованный выпад, и кстати, не только в сторону Джеффри Рихтера...
W>]

W>[

W>Переписка из блога.

>>>Они похожи на деструкторы C++

>>>— в результате, программисты пишут и думают себе что-то одно, а получается ОЧЕНЬ другое

W>Я не знаю, о чем думают программисты, когда пишут свой код, но явно не о Рихтере... И приведенный выше фрагмент в моей интерпретации это полностью доказывает.


>>>Они вызываются в нефиксированный момент времени

>>>— при отладке в условиях A мы видим одно поведение, а при реальной работе в условиях B имеем совсем другое

W>Именно об этом нам и пишет Рихтер. Кратко но _доходчиво_ разъясняя технические аспекты. Вот этот отрывок (это мой литературный перевод, можете cверить с "настоящим" русским изданием, вполне возможно, там содержатся ошибки, которые и ведут к оказиям):


W>"

W>Примечание.
W>В таблице 19-1 обратите внимание, что на аргумент arg1 нашего метода больше никто не ссылается после инструкций процессора со смещением 0x00000020. Это значит, что объект arg1 помечается как "пригодный для сборки в любое время" после выполнения этих инструкций (предполагается, что в приложении больше нет корневых элементов, которые ссылаются на этот объект). Другими словами, как только объект становится недостижимым [чтобы понять смысл этой фразы, нужно читнуть пару абзацев выше, но эти потуги я уже возложу на плечи наших "учеников"], он превращается в кандидата на сборку, поэтому не гарантируется, что объекты будут жить на протяжении всего времени выполнения метода.
W>[Дальше пошло самое вкусное.]
W>Одако, когда приложение выполняется через отладчик, или когда сборка помечена атрибутом System.Diagnostics.DebuggableAttribute с параметром isJITOptimizerDisabled выставленным в true, компилятор JIT продлевает время жизни всех переменных (будь то типы, передающиеся по значению или по ссылке) до окончания их области видимости, что в большинстве случаев означает конец самого метода. (Между прочим, компилятор C#, при использовании ключа /debug в командной строке, помечает сборку атрибутом DebuggerAttribute, устанавливая параметр isJITOptimizerDisabled в true.) Это расширение предотвращает сборщика мусора от сборки ссылочных типов во время выполнения кода в данной области видимости, что полезно при отладке. Было бы совсем неуместно, если бы вы вызвали метод объекта, получили неправильный результат, а затем не смогли бы даже взглянуть на этот объект!
W>"

W>Рихтер сказал один в один по писаному... Или наоборот.

W>]

W>P.S. Рихтер, как известно, на короткой ноге с Microsoft. И я очень сильно сомневаюсь, что кто-то намного лучше самих майкрософтовцев знает, как пользоваться их продуктами. Поэтому бороться если и надо, то не с Рихтером, а с гореучениками, которые не в состоянии уловить мысль человека до конца. Повышать, так сказать, уровень базовых знаний (и в руки Рихтера не давать!). А то человек оперирует таким понятиями, как "функция memcpy", "регистр процессора", хотя для многих "начинающих" это звучит как заклинание. Тогда о каком чтении Рихтера может идти речь? Нужно брать что-то более научно-популярное... Хотя мне кажется, что если читатель толковый, то, дочитав до незнакомого слова, полезет в нет и разберется, что к чему. Это даже способствует повышению уровня своего развития. И не только в сторону освоения .NET. Так что IMHO рано-то Рихтера на свалку истории списывать... Превзойти своего учителя это похвально, вот только не нужно унижать его талант.


Откуда вы вообще можете знать, позвольте Вас спросить, как я отношусь к Рихтеру, и к тому, что он пишет? Я вообще-то привык всегда подвергать критике и осмыслению то, что пишется и говорится, невзирая на авторитеты. По поводу финализаторов приведу идин из своих постов до этого: http://rsdn.ru/Forum/Message.aspx?mid=1642314&amp;only=1
Автор: Alexander__S
Дата: 27.01.06


W>Alexander__S >>Финлазиторы плохи, спору нет. Но за все надо платить, в том числе и за GC.


W>Они не плохи. Просто ко всему нужно подходить с головой. Сначала работает голова, и только потом руки. Тогда все будет путем.


Может быть, укажете примеры использования мной финализаторв с преждевреммой работой рук?
А финализаторы полохи, не буду сейчас говорить про SafeHandle, но в FW 1.1 я бы постарался избежать их использования. Да об этом и писали уже здесь: http://rsdn.ru/Forum/Message.aspx?mid=1610417&amp;only=1
Автор: AndrewVK
Дата: 24.01.06
Re[8]: Правила использования финалайзеров [blog]
От: mihailik Украина  
Дата: 29.01.06 20:55
Оценка:
A__>Первый вопрос: зачем Вы вывалили это...

Скорее, это был ответ на мой начальный пост. Цитаты — оттуда.

Видимо, eisernWolf читает нас не из древовидного представления.

Но мысли толковые. Я не согласен, конечно, но всё равно в хорошую сторону подтолкнул. Так что свои баллы я поставил
Re[7]: Правила использования финалайзеров [blog]
От: Alexander__S  
Дата: 29.01.06 20:57
Оценка:
Хм... "Разрушитель мифов", поучающий несмышленных программеров, "предпочитающих что-то слащаво-подростковое, например Рихтера"

Кому бы меня и поучать, извиняюсь, да только не Вам
Re[20]: Правила использования финалайзеров [blog]
От: Hacker_Delphi Россия  
Дата: 30.01.06 05:43
Оценка:
Здравствуйте, mihailik, Вы писали:

M>Тут ты ошибся. Даже не в деталях, а в корне ошибся.


M>Если твой объект "держит" ссылки на другие управляемые объекты, то финализатор вообще не поможет. Когда твой объект будет мусором, то он уже не будет "держать" никого. Есть ли из него ссылки, нет ли — уже никого не волнует. Мёртвые не потеют.


M>Если же говорить о частностях, то WeakReference не считаются ссылками и не мешают объектам становится мусором.

да не держит он никого... вернее тот кого он держит живет однозначно дольше его.
просто из этого кого-то надо WeakReference убить на уничтожаемый объект — вот и все.
чтобы в Cache не лежало битых ссылок Конечно, при поиске объекта в Cache я чищу эти битые ссылки, но если можно заранее их почистить....
Речь идет про финализатор того объекта "на который" есть WeakReference.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Если при компиляции и исполнении вашей программы не происходит ни одной ошибки — это ошибка компилятора :)))
Re[21]: Правила использования финалайзеров [blog]
От: mihailik Украина  
Дата: 30.01.06 12:01
Оценка:
H_D>просто из этого кого-то надо WeakReference убить на уничтожаемый объект — вот и все.
H_D>чтобы в Cache не лежало битых ссылок

Нет, это неправильно.

Финализация накладывает на систему существенные накладные расходы. Такие "подчистки" не оправдывают использование финализации.
Re[22]: Правила использования финалайзеров [blog]
От: Hacker_Delphi Россия  
Дата: 30.01.06 12:37
Оценка:
Здравствуйте, mihailik, Вы писали:

M>Финализация накладывает на систему существенные накладные расходы. Такие "подчистки" не оправдывают использование финализации.


гы. Если не делать таких чисток — у меня обращения к кэшу будут вызывать море накладных расходов...
Проверено — так работает быстрее и в случае Application mode GC и в случае Service Mode.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Если при компиляции и исполнении вашей программы не происходит ни одной ошибки — это ошибка компилятора :)))
Re[6]: Правила использования финалайзеров [blog]
От: vdimas Россия  
Дата: 30.01.06 19:33
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, vdimas, Вы писали:

V>>Потому как доступ к полу disposed в этом случае следовало бы сделать блокируемым. Я понимаю, что вряд ли у кого-то получится явно задиспозить из другого потока в момент финализации, но мало-ли что...
S>В момент финализации задиспозить ни из какого потока не "вряд ли", а невозможно. Потому что в очередь финализации попадают только те объекты, на которые уже нет ссылок.

Я имел в виду WeakReference конечно

V>>Булевская локальная переменная — вполне себе выдержана в духе обычного локального контекста для конкурирующих потоков.

S>Ты, похоже, смешал в кучу параметр disposing и поле disposed, которые имеют совершенно различный смысл и используются независимо. Перечитай еще раз пример.

Да нет, не смешал. Еще раз — представь себе ситуацию конкурирующего вызова disposing. Передача булевского флага позволяет обойтись БЕЗ блокировок, ибо со значением false будет вызван только из одного потока.
Re[23]: Правила использования финалайзеров [blog]
От: mihailik Украина  
Дата: 30.01.06 22:31
Оценка:
M>>Финализация накладывает на систему существенные накладные расходы. Такие "подчистки" не оправдывают использование финализации.

H_D>гы. Если не делать таких чисток — у меня обращения к кэшу будут вызывать море накладных расходов...

H_D>Проверено — так работает быстрее и в случае Application mode GC и в случае Service Mode.

Если так, то похоже на то, что где-то архитектура кривовата.

Но раз работает — лучше не трогать
Re[7]: Правила использования финалайзеров [blog]
От: Sinclair Россия https://github.com/evilguest/
Дата: 31.01.06 04:18
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Я имел в виду WeakReference конечно

И? Неужели в присутствии WeakReference фреймворк будет вызывать финалайзеры у достижимых объектов? Это что-то новое для меня.
V>Да нет, не смешал. Еще раз — представь себе ситуацию конкурирующего вызова disposing. Передача булевского флага позволяет обойтись БЕЗ блокировок, ибо со значением false будет вызван только из одного потока.
Представил. Гонишь. Еще раз перечитай код:
public void Dispose()
{
  Dispose(true);
  GC.SuppressFinalize(this);
}

Ну и где здесь гарантия невызова из другого потока? Либо я дурак, либо ты что-то очень сильно путаешь.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Правила использования финалайзеров [blog]
От: vdimas Россия  
Дата: 31.01.06 08:32
Оценка:
S>Представил. Гонишь. Еще раз перечитай код:
S>
S>public void Dispose()
S>{
S>  Dispose(true);
S>  GC.SuppressFinalize(this);
S>}
S>

S>Ну и где здесь гарантия невызова из другого потока? Либо я дурак, либо ты что-то очень сильно путаешь.

Сам перечитай еще раз. У нас есть гарантия невызова из другого потока со значением False, т.е. в этом случае можно обойтись без блокировки. А в случае твоего флага _disposed — нужна блокировка во всех случаях.
Re[9]: Правила использования финалайзеров [blog]
От: Sinclair Россия https://github.com/evilguest/
Дата: 31.01.06 09:10
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Сам перечитай еще раз. У нас есть гарантия невызова из другого потока со значением False, т.е. в этом случае можно обойтись без блокировки. А в случае твоего флага _disposed — нужна блокировка во всех случаях.

Ок, я начинаю понимать твою мысль. Для полноты картины, не мог ли бы ты воспользоваться этим знанием и обойтись без блокировки:
protected virtual void Dispose(bool disposing)
{
    if(!this.disposed)
    {
    if(disposing)
    {
        Components.Dispose();
    }
    CloseHandle(handle);
    handle = IntPtr.Zero;
    // Note that this is not thread safe.
    // Another thread could start disposing the object
    // after the managed resources are disposed,
    // but before the disposed flag is set to true.
    // If thread safety is necessary, it must be
    // implemented by the client.
    }
    disposed = true;         
}
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[24]: Правила использования финалайзеров [blog]
От: Hacker_Delphi Россия  
Дата: 01.02.06 09:34
Оценка:
Здравствуйте, mihailik, Вы писали:

M>Если так, то похоже на то, что где-то архитектура кривовата.


M>Но раз работает — лучше не трогать


Гм. при чем здесь архитектура?
WeakReference для того, чтобы GC решал когда Cache надо "подчищать" — вроде бы нормально
Hashtable для поиска по ID — тоже нормально...
вычистить "мертвые" ссылки при "смерти" объекта — просто необходимо...
что не так в архитектуре?
Да, при более менее таком интенсивном использовании CacheHit составляет примерно 60 % — это при политике Service обслуживания GC.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Если при компиляции и исполнении вашей программы не происходит ни одной ошибки — это ошибка компилятора :)))
Re[25]: Правила использования финалайзеров [blog]
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.02.06 14:21
Оценка: +1
Здравствуйте, Hacker_Delphi, Вы писали:
H_D>Гм. при чем здесь архитектура?
H_D>WeakReference для того, чтобы GC решал когда Cache надо "подчищать" — вроде бы нормально
Это верно. Точнее, скажем так: WeakReference — для того, чтобы не удерживать объект.
H_D>Hashtable для поиска по ID — тоже нормально...
H_D>вычистить "мертвые" ссылки при "смерти" объекта — просто необходимо...
А вот это уже заблуждение. Любое использование слабых ссылок предполагает возможность в любой момент потерять эту ссылку. Проектировать другим способом — нарываться на неприятности. Я вот не могу понять выигрыша от принудительного оповещения всех заинтересованных объектов о смерти слабой ссылки. Неужели вызов IsAlive при каждом обращении так дорог? При этом у тебя финалайзер выполняет работу порядка O() от количества слабых ссылок на умирающий объект. Что чревато нехорошими последствиями.
H_D>что не так в архитектуре?
H_D>Да, при более менее таком интенсивном использовании CacheHit составляет примерно 60 % — это при политике Service обслуживания GC.
CacheHit, очевидно, никак не зависит от того, в какой момент происходит детектирование пропажи слабой ссылки. Если зависит — то косяк в архитектуре.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.