Как я могу избавиться от объекта (скажем, растрового изображения), когда он становится осиротевшим?

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

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

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

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

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

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

1 - когда Bitmap выгнали из очереди в классе A

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

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

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

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

4 ответа

Решение

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам