До сих пор я всегда использовал pixDestroy для очистки объектов PIX в моем Приложение JavaCPP/Leptonica. Однако недавно я заметил странную проблему с утечкой памяти, которую я обнаружил в функции Leptonica, которая внутренне возвращает результат pixClone. Мне удалось воспроизвести проблему с помощью следующего простого теста:
@Test
public void test() throws InterruptedException {
String pathImg = "...";
for (int i = 0; i < 100; i++) {
PIX img = pixRead(pathImg);
PIX clone = pixClone(img);
pixDestroy(clone);
pixDestroy(img);
}
Thread.sleep(10000);
}
Когда достигается Thread.sleep, использование оперативной памяти в диспетчере задач Windows (не размер кучи) увеличивается примерно до 1 ГБ и не освобождается до тех пор, пока не закончится спящий режим и не завершится тест.
Глядя на документы pixClone, мы видим, что он фактически создает дескриптор для существующий PIX:
Заметки:
«Клон» — это просто дескриптор (ptr) существующего изображения. Это реализовано, потому что (а) изображения могут быть большими и, следовательно, дорогими для копирования, и (б) дополнительные дескрипторы структуры данных должны быть сделаны с помощью простой политики, чтобы избежать как двойных освобождений, так и утечек памяти. Пикс подсчитывается по ссылкам. Побочным эффектом pixClone() является увеличение счетчика ссылок на 1.
Следует использовать следующий протокол: (a) Всякий раз, когда вам нужен новый дескриптор существующего изображения, вызывайте pixClone(), который просто увеличивает количество ссылок. (b) Всегда вызывайте pixDestroy() для всех дескрипторов. Это уменьшает счетчик ссылок, обнуляет дескриптор и уничтожает пикс только тогда, когда pixDestroy() вызывается для всех дескрипторов.
Если я правильно понимаю, я действительно вызываю pixDestroy для всех дескрипторов, поэтому счетчик ссылок должен достичь нуля и, следовательно, PIX должен быть уничтожен. Хотя ясно, что это не так. Может кто-нибудь сказать мне, что я делаю неправильно? Заранее спасибо!