Требуется такая логика работы:
Есть некий объект ResourceManager. По первому требованию от клиентского кода ResourceManager создёт некотрый объект Resource. Последующие запросы этого же ресурса другими клиентами возвращают тот же объект Resource. Когда все клиенты освободили ссылки на ресурс, объект Resource должен освободить занимаесые им физические ресурсы.
Проблема в реализации последнего требования: клиенты не имеют права вызывать Dispose у объекта Resource (ресурс совместно используется несколькими независимыми клиентами), а GC может вообще никогда не добраться до объекта Resource. Хотелось бы чтобы Resource освободил физические ресурсы сразу после исчезновения последного клиента.
Здравствуйте, Аноним, Вы писали:
А>Требуется такая логика работы: А>Есть некий объект ResourceManager. По первому требованию от клиентского кода ResourceManager создёт некотрый объект Resource. Последующие запросы этого же ресурса другими клиентами возвращают тот же объект Resource. Когда все клиенты освободили ссылки на ресурс, объект Resource должен освободить занимаесые им физические ресурсы.
А>Проблема в реализации последнего требования: клиенты не имеют права вызывать Dispose у объекта Resource (ресурс совместно используется несколькими независимыми клиентами), а GC может вообще никогда не добраться до объекта Resource. Хотелось бы чтобы Resource освободил физические ресурсы сразу после исчезновения последного клиента.
пусть клиенты вызывают Dispose на здоровье, а ты поставь собственный счетчик ссылок на ресурс и прибивай ресурс в вызове последнего Dispos`а.
PS
и не путай Dispose с деструктором.
PS PS
а между удалением последней ссылки на объект и его автоматической сборкой может пройти уйма времени.
Re[2]: Вопрос про GC и ресурсы
От:
Аноним
Дата:
22.02.06 11:27
Оценка:
A>пусть клиенты вызывают Dispose на здоровье, а ты поставь собственный счетчик ссылок на ресурс и прибивай ресурс в вызове последнего Dispos`а.
Тогда нужно абязать клиентов вызывать некий AddRef, парный Dispose(). Ведь клиенты могут передавть ссылку на ресурс друг гругу. Вообще-то это криво: возвращяться к глючному ручному подсчёту ссылок в стиле "COM без смарт-указателей".
A>PS A>и не путай Dispose с деструктором.
С чего ты взял что я не путаю. Если следовать общепринятой семантике Dispose, то этот метод должен перевести объект в некое предсмертное состояние, в котором при любом вызов приводит к ObjectDisposedException. Это вряд ли понравится остальным клиентам.
A>PS PS A>а между удалением последней ссылки на объект и его автоматической сборкой может пройти уйма времени.
Я об этом и писал: "GC может вообще никогда не добраться до объекта Resource".
A>>пусть клиенты вызывают Dispose на здоровье, а ты поставь собственный счетчик ссылок на ресурс и прибивай ресурс в вызове последнего Dispos`а. А>Тогда нужно абязать клиентов вызывать некий AddRef, парный Dispose(). Ведь клиенты могут передавть ссылку на ресурс друг гругу. Вообще-то это криво: возвращяться к глючному ручному подсчёту ссылок в стиле "COM без смарт-указателей".
где ж тут кривизна? все вызовы создания проходят через ResourceManager, пусть и все вызовы удаления через него проходят — подсчет ссылок не составит труда.
A>>и не путай Dispose с деструктором. А>С чего ты взял что я не путаю. Если следовать общепринятой семантике Dispose, то этот метод должен перевести объект в некое предсмертное состояние, в котором при любом вызов приводит к ObjectDisposedException.
по моему, это не так. хотя я могу ошибаться...
вот код. вроде не падает...
System.Drawing.SolidBrush br = new SolidBrush(Color.LightGreen);
br.Dispose();
br.Dispose();
A>>пусть клиенты вызывают Dispose на здоровье, а ты поставь собственный счетчик ссылок на ресурс и прибивай ресурс в вызове последнего Dispos`а. А>Тогда нужно абязать клиентов вызывать некий AddRef, парный Dispose(). Ведь клиенты могут передавть ссылку на ресурс друг гругу. Вообще-то это криво: возвращяться к глючному ручному подсчёту ссылок в стиле "COM без смарт-указателей".
Мне очень нравится, что задачу, сформированную в терминах подсчета ссылок, решать с помощью подсчета ссылок ты считаешь кривым подходом.
Механизм сборки мусора под твою задачу не подходит. Он идеологически другой. Ты это понимаешь? Поэтому правильным подходом можно считать конструкцию вида using. Если тебя колбасит от нецелевого Dispose — сделай этот объект "оберткой" над собственно ресурсом. Например.
Здравствуйте, mrozov, Вы писали:
M>Мне очень нравится, что задачу, сформированную в терминах подсчета ссылок, решать с помощью подсчета ссылок ты считаешь кривым подходом.
Разве автор вопроса сказал, что его интересует число клиентов использующих его ресурс?
Использование подсчета ссылок на ресурс неблагодарное занятие, особенно когда ссылка на ресурс начинает "гулять" по всему приложению, и контроль ссылок с пом. всяких AddRef и ReleseRef будет просто адом.
M>Механизм сборки мусора под твою задачу не подходит. Он идеологически другой.
Еще как подходит.
Один из вариантов решения проблемы: ResourceManager хранит к кэше требуемый ресурс, а также связанный с этим ресурсом список тех, кто его использует (назовем их владельцы ресурса), в списке хряняться слабые ссылки на владельцев (используя WeakReference). Периодически кэш сканируется, и как только последний владелец ресурса "умрет", удаляем ресурс.
Здравствуйте, AlexZu, Вы писали:
M>>Механизм сборки мусора под твою задачу не подходит. Он идеологически другой. AZ>Еще как подходит. AZ>Один из вариантов решения проблемы: ResourceManager хранит к кэше требуемый ресурс, а также связанный с этим ресурсом список тех, кто его использует (назовем их владельцы ресурса), в списке хряняться слабые ссылки на владельцев (используя WeakReference). Периодически кэш сканируется, и как только последний владелец ресурса "умрет", удаляем ресурс.
Автор вопроса не уверен в том, когда именно сборщик мусора собирет его ресурсы(или их обертки). Ты ему предлагаешь подождать сборки вообще третьих объектов, которые (между прочим) ты предлагаешь передавать каким-то образом в ResourceManager при создании (запросе) ресурса...
это чем-то напоминает работу GC. только в кривом исполнении.
лови -1.
Здравствуйте, andreich78, Вы писали:
A>Здравствуйте, AlexZu, Вы писали:
AZ>>Еще как подходит. AZ>>Один из вариантов решения проблемы: ResourceManager хранит к кэше требуемый ресурс, а также связанный с этим ресурсом список тех, кто его использует (назовем их владельцы ресурса), в списке хряняться слабые ссылки на владельцев (используя WeakReference). Периодически кэш сканируется, и как только последний владелец ресурса "умрет", удаляем ресурс.
A>Автор вопроса не уверен в том, когда именно сборщик мусора собирет его ресурсы(или их обертки). Ты ему предлагаешь подождать сборки вообще третьих объектов, которые (между прочим) ты предлагаешь передавать каким-то образом в ResourceManager при создании (запросе) ресурса...
Очень идеалистично рассуждаете:
А теперь давайте на секундочку представим: у тебя проект: 75 сборок и 1 сборка ресурсов, в ней, скажем, помимо прочего, более 150 иконок, которые используются всеми этими сборками. Одну иконку может юзать более чем одина сборка(иначе зачем бы это все затевалось). Представили?
Ваше предолжение, насколько я понял,это AddRef и ReleaseRef (using не подходит однозначно).
Большой его минус:
Забыл AddRef или ReleaseRef (а вероятность ОЧЕНЬ велика, да и не всегда прозрачно, где вызывать ReleaseRef) — все — ресурс повис. Как вы это будите дебажить? Сколько вы времени потеряете?
По поводу "кривого исполнения" — ну эт зависит от исполнителя, как понимаете. Либо поясните в чем "кривизна"?
Здравствуйте, andreich78, Вы писали:
A>Автор вопроса не уверен в том, когда именно сборщик мусора собирет его ресурсы(или их обертки).
В исходном сообщени об этом нет речи. GC соберт объект-ресурс тогда, когда ему это позволит ResourceManager, поскольку он держит сильную ссылку на ресурс. И задача для ResourceManager в том, чтобы определить, в какой момент можно освободить ресурс.
A>Ты ему предлагаешь подождать сборки вообще третьих объектов, которые (между прочим) ты предлагаешь передавать каким-то образом в ResourceManager при создании (запросе) ресурса...
Именнно так. Объекты таким образом дают знать ResourceManager'у о своем желании поюзать ресурс, и пока живы эти объекты (или напр. не отписались от использования ресурса), ресурс должен быть валидным. A>это чем-то напоминает работу GC. только в кривом исполнении.
и что таки предлагаешь?
Как я поминаю WeakReference на клиента нельзя считать стопроцентным детектром существования клиента. Ведь WeakReference обнуляется сборщиком мусора. А когда сборщик доберётся до клиентов также неизвестно как и в случае объекта Resource. Клиент уже может быть давно ждёт своей участи в Finalization Queue, но при этом WeakReference на него ещё действителен.
Бред.
Если полагаться на сборщик мусора,то весь описанный тобой кривой механизм не нужен. Сборщик мусора все сделает сам.
Если на сборщик мусора НЕ полагаться, то без явного управления ссылками решить задачу все равно нельзя. Твой кривой подход в этом смысле ничего кроме лишней сложности не дает. То есть вообще — полный 0 — ничего полезного он не делает, только пыхтит.
Здравствуйте, mrozov, Вы писали:
M>Бред.
Тю...
M>Если полагаться на сборщик мусора,то весь описанный тобой кривой механизм не нужен. Сборщик мусора все сделает сам.
Действительно, в описанной задаче ResourceManager вполне мог хранить слабые ссылки на ресурс, перидичесски сканируя кэш на предмет "мертвых" ресурсов, полагаясь на GC который когда-нибудь вызовет финализатор, в котором будут освобождены неуправляемые ресурсы.
недостатки:
1) ResourceManager узнает что объект-ресурс собран GC не сразу, если канешна сам ресурс не уведомит его из финализатора (что есть источник возможных проблем, поэтому не рассматриваем этот вариант)
2) нет возможности управлять политиками времени жизни ресурса, т.к. политика только одна: на объект нет боле сильных ссылок.
Попробую продемонстрировать их на примере:
1) Если при запросе каким-нить клиентом определенного ресурса ResourceManager определяет, что ресурс "мертв",
он попытается создать новый экземпляр ресурса.
А теперь представьте, что ресурс это соединенине с удаленным сервером, которое может быть в только одном экземпляре. У ресурса еще не был вызван финализатор, но для ResourceManager он уже "мертв". ResourceManager будет пытаться создать соединение, но попытка окончится неудачей, поскольку предыдущее соединени не было разорвано.
2) Отсутствие на объект сильных ссылок может быть недостаточным для удаления ресурса. Напр. ResourceManager может вести статистику использования ресурса, и после исчезновения последней ссылки на ресурс, он может "подержать" ресурс в кэше еще какое-нить время.
Все эти недостатки решаются используя описанный мной подход ранее.
На 1-й взгляд может показаться, что там делается та же работа, которую делает GC, и это почти так...почти, да не совсем, т.к. в данном случае мы управляем временем жизни ресурса, и это самое важное.
Резюмируя: Нельзя полагаться на GC когда речь идет о НЕУПРАВЛЯЕМЫХ ресурсах, наличие финализатора у оболочек над неуправляемыми ресурсами это как последний шанс освободить ресурс, но никак не команда к действию. Ресурс должен освобождаться вручную.
M>Если на сборщик мусора НЕ полагаться, то без явного управления ссылками решить задачу все равно нельзя. никаких счетчиков!, только используя слабые ссылки
M>Твой кривой подход в этом смысле ничего кроме лишней сложности не дает. То есть вообще — полный 0 — ничего полезного он не делает, только пыхтит.
А ежели все-же напрячься и подумать?
Здравствуйте, Аноним, Вы писали:
А>Требуется такая логика работы: А>Есть некий объект ResourceManager. По первому требованию от клиентского кода ResourceManager создёт некотрый объект Resource. Последующие запросы этого же ресурса другими клиентами возвращают тот же объект Resource. Когда все клиенты освободили ссылки на ресурс, объект Resource должен освободить занимаесые им физические ресурсы.
А>Проблема в реализации последнего требования: клиенты не имеют права вызывать Dispose у объекта Resource (ресурс совместно используется несколькими независимыми клиентами), а GC может вообще никогда не добраться до объекта Resource. Хотелось бы чтобы Resource освободил физические ресурсы сразу после исчезновения последного клиента.
А что за ресурсы-то? И кто их потребляет?
Вообще задача туманна, например, "возвращают тот же объект Resource". Это может делаться разными методами. Один уже был предложен — слабые ссылки. Относительно обычных ссылок общая идея конечно addref/release, но чтобы не сойти с ума с подсчетами ссылок, сделать можно так:
— менеджер хранит ресурсы
— клиент хочет попользовать ресурс, он зовет метод, возвращающий IDisposable объект (хранитель), хрянящий у себя требуемый ресурс
— вызов данного метода (и получение хранителя) у клиента происходит внутри using — чтобы не забыть освободить
— хранитель в Dispose обнуляет ссылку