Как я могу избавиться от объекта (скажем, растрового изображения), когда он становится осиротевшим? - PullRequest
4 голосов
/ 26 марта 2010

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

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

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

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

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

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

1 - когда растровое изображение выбрасывается из очереди в классе A

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

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

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

Любой совет будет приветствоваться.

Ответы [ 4 ]

3 голосов
/ 26 марта 2010

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

2 голосов
/ 26 марта 2010

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

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

1 голос
/ 26 марта 2010

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

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

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

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

0 голосов
/ 26 марта 2010

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

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

...