2010-03-26 4 views
4

У меня есть класс A, обеспечивающий растровые изображения для других классов B, C и т. Д.Как я могу избавиться от объекта (скажем Bitmap), когда он становится сиротой?

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

Пока он находится в очереди, тот же битмап может быть проверен несколькими классами, так что, скажем, B и C могут удерживать ссылку на этот же битмап. Но также может случиться так, что только один из них проверил битмап или даже ни один из них.

Я хотел бы избавиться от растрового изображения, когда он не нужен больше либо A, B или C.

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

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

1 - когда Bitmap пинают из очереди в классе А

2 - когда B закончит с ним

3 - когда C закончит с ним

Если это лучшая стратегия, как я могу оценить состояние сироту?

Любые советы были бы очень желанными.

+0

Это помогло бы, если бы вы могли уточнить, поддерживают ли классы A, B и C ссылку на растровое изображение, когда они закончили с ним, оставив только очередь со ссылкой. – tames

+0

@tames: Это на самом деле то, что открыто для совета. Я хочу принять соответствующую стратегию, которую могут рекомендовать ответчики. –

ответ

3

Имейте класс A, чтобы обеспечить класс оболочки, а не растровое изображение. Класс-оболочка должен реализовать IDisposable сам и может использоваться для поддержания счетчика. Каждый потребитель может получить свою собственную оболочку, которая ссылается на один битмап. Класс A сохраняет ловушку всех растровых изображений и всех оберток. Используйте WeakReference в классе A, чтобы отслеживать обертки, поэтому, если потребитель не вызывает dispose, он получит GC'd, и поставщик может знать, что он больше не ссылается.

+0

Подсчет ссылок - правильная идея. WeakReference - это не так. Это резервная копия кода, забывающая вызвать Dispose. Который удерживает битмап, не слишком длинный, создавая точную проблему, которую пытается решить ОП. Ref-counting * требует * a Dispose, обнаружение отсутствующего должно генерировать исключение. –

+0

@nobugz, я согласен, WeakReference - это разрыв пробела. Нет никакого способа, чтобы ** потребовать, чтобы вызывающий вызывал вызов Dispose. Зайти в финализатор было бы неплохо, но я бы не стал игнорировать WeakReference, потому что он не должен использоваться. Требование Dispose может закончиться утечкой, которую избежит WeakReference (что хорошо, если утечка не попадает в dev/testing, а только на поверхности). –

+0

Ну, есть: «Я буду бомбить программу, если вы этого не сделаете». В конечном счете это слабость схем подсчета ссылок, лучше просто не делать этого. –

2

Bitmap наследует от Image, который реализует IDisposable, поэтому, когда вы закончите использовать экземпляр, вы должны позвонить ему Dispose(). Это очистит неуправляемый ресурс в Image.

Однако, Image также реализует финализатор, поэтому, если по какой-либо причине вы не можете позвонить Dispose(), ресурс будет восстановлен во время финализации экземпляра, который произойдет в какой-то момент после того, как экземпляр больше не ссылается.

+1

Я думаю, что вопрос заключался в том, как узнать, когда вызывать Dispose(), когда у вас есть несколько пользователей, которые используют одно и то же растровое изображение. –

+0

Да, я пытаюсь избавиться от растрового изображения, как только он перестанет использоваться его потребителями. –

+0

@Jelly: Я понял, но у меня также сложилось впечатление, что вы не могли определить, когда объект больше не нужен, и поэтому не сможет вызвать Dispose(). Если это так, финализатор будет действовать как откат, когда экземпляр больше не ссылается. –

1

Если использование памяти не такая большая проблема, и правильность и ясность более важны ...

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

Ваш код управления теперь очень прост, и ваш код потребления также очень прост. Также очень легко увидеть (доказать?), Что все это будет работать, даже если у ваших потребителей могут быть исключения и другие пути кода, что затрудняет (или невозможно) уверенность в том, что счетчики ссылок были уменьшены (или такие как).

Используя время, которое вы сохранили, разработали собственное решение GC для общих растровых изображений, возьмите деньги и купите еще один палец ОЗУ для вашего сервера.

+0

К сожалению, память является основной проблемой, так как будет много экземпляров этого класса провайдера изображений A, и мне нужно обрезать потребление памяти, чтобы не полагаться на GC и получать всплески производительности. Извините, я должен был объяснить, что это для реального времени, а не для серверного приложения. –

+0

Не обязательно, чтобы этот подход был «хуже» с точки зрения времени, проведенного в GC. Если эти клонированные объекты имеют короткий срок службы, так что они загружаются во время GC (0), тогда затраты на сбор мусора будут небольшими. В любом случае, поскольку они, вероятно, будут на LOH, они не будут перемещаться в памяти после выделения. –

0

Если, с другой стороны, потребление пиковой памяти является ключевой проблемой ... но вы по-прежнему хотите «безопасный» подход, когда вы можете быть уверены, что время жизни растровых изображений управляется должным образом, независимо от кода потребителя, который вы могли бы инвертировать проблему и сказать, что производитель несет полную ответственность за все операции над изображениями в своем потоке (или потоках). Поэтому вместо того, чтобы передавать изображения другим классам, над которыми вы работаете, вы просите другие классы передать действия для выполнения на изображениях. Вы поддерживаете очередь ожидающих действий и можете заглядывать вперед в очередь, чтобы решить, какие изображения нужно бросить из буфера, основываясь на отсутствии дальнейшей работы над ними.

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