Хотя DropHandler не удаляется из статической карты AppContext, на самом деле это не основная причина, а лишь одна из причин в цепочке. (Обработчик отбрасывания должен быть одноэлементным и не очищаться до тех пор, пока класс AppContext не будет выгружен, чего на практике никогда не бывает.) Использование одноэлементного DropHandler разработано специально.
Настоящая причина утечки заключается в том, что DropHandler устанавливает экземпляр TransferSupport, который повторно используется для каждой операции DnD, а во время операции DnD предоставляет ему ссылку на компонент, участвующий в DnD. Проблема в том, что не очищает ссылку, когда DnD заканчивает . Если DropHandler вызовет TransferSupport.setDNDVariables(null,null)
, когда DnD выйдет, то проблема исчезнет. Это также наиболее логичное решение, поскольку ссылка на компонент требуется только во время выполнения DnD. Другие подходы, такие как очистка карты AppContext, обходят дизайн, а не исправляют небольшой недосмотр.
Но даже если мы исправим это, кадр все равно не будет собран. К сожалению, кажется, есть другая проблема: когда я закомментировал весь код, связанный с DnD, сводя его к простому JFrame, он тоже не собирался. Ссылка на возврат был в javax.swing.BufferStrategyPaintManager
. Для этого есть отчет об ошибке , который еще не исправлен.
Итак, если мы исправим DnD, мы столкнемся с другой проблемой хранения с перерисовкой. К счастью, все эти ошибки держатся только на одном кадре (надеюсь, на одном и том же!), Так что это не так плохо, как могло бы быть. Фрейм располагается таким образом, что исходные ресурсы освобождаются, и весь контент может быть удален, что позволяет его освободить, уменьшая серьезность утечки памяти.
Итак, чтобы окончательно ответить на ваш вопрос, вы не делаете ничего плохого, вы просто даете некоторым ошибкам в JDK немного эфирного времени!
ОБНОВЛЕНИЕ: Исправлена ошибка в менеджере перерисовок - добавление
-Dswing.bufferPerWindow=false
В опциях запуска jvm ошибка отсутствует. После устранения этой ошибки имеет смысл опубликовать исправление ошибки DnD:
Чтобы исправить проблему DnD, вы можете добавить вызов этого метода в конце importData ().
private void cancelDnD(TransferSupport support)
{
/*TransferSupport.setDNDVariables(Component component, DropTargetEvent event)
Call setDNDVariables(null, null) to free the component.
*/
try
{
Method m = support.getClass().getDeclaredMethod("setDNDVariables", new Class[] { Component.class, DropTargetEvent.class });
m.setAccessible(true);
m.invoke(support, null, null);
System.out.println("cancelledDnd");
}
catch (Exception e)
{
}
}