Определить, кто создал тему (w. Eclipse)
Как я могу узнать, кто создал тему в Java?
Представьте себе следующее: вы используете ~30 сторонних JAR-файлов в сложной среде плагина. Вы запускаете его, запускаете много кода, выполняете некоторые вычисления и, наконец, вызываете shutdown().
Этот жизненный цикл обычно работает нормально, за исключением того, что при каждом запуске некоторые (не демонические) потоки остаются висящими. Это не было бы проблемой, если бы каждое выключение было последним выключением, я мог бы просто запустить System.exit() в этом случае. Однако этот цикл может выполняться несколько раз, и он производит больше мусора за каждый проход.
И что же мне делать? Я вижу темы в представлении отладки Eclipse. Я вижу их следы стека, но они не содержат никаких намеков на их происхождение. Нет трассировки стека создателя, нет различимого имени класса, ничего.
У кого-нибудь есть идеи, как решить эту проблему?
4 ответа
Хорошо, я смог решить (вроде) проблему самостоятельно: я поставил точку останова в
Thread.start()
и вручную проходил через каждый вызов. Таким образом, я довольно быстро обнаружил, что Class.forName() инициализировал много статического кода, который в свою очередь создал эти таинственные потоки.
Хотя я смог решить свою проблему, я все еще думаю, что более общая задача все еще остается без внимания.
Я неукоснительно называю свои потоки (скажем, используя Thread(Runnable, String)), в противном случае они заканчиваются общим и несколько бесполезным именем. Сброс потоков будет подсвечивать то, что работает и (таким образом), что их создало. Я не ценю создание сторонних потоков.
РЕДАКТИРОВАТЬ: бюллетень JavaSpecialist недавно обратился к этой проблеме (февраль 2015 года) с помощью диспетчера безопасности. Смотрите здесь для более подробной информации
Еще: Несколько деталей для использования техники JavaSpecialist: API SecurityManager включает в себя "checkAccess(newThreadBeingCreated)", который вызывается в потоке создателя потока. Новый поток уже имеет инициализированное имя. Таким образом, в этом методе у вас есть доступ как к потоку создателя потока, так и к новому, и вы можете регистрировать / печатать и т. Д. Когда я попытался это сделать, отслеживаемый код начал генерировать исключения защиты доступа; Я исправил это, вызвав его в AccessController.doPriviledged(new PrivilegedAction() { ... }, где метод run() вызвал отслеживаемый код).
В целях локальной отладки можно как можно раньше подключить отладчик к приложению Java.
Установите точку останова без приостановки в концеjava.lang.Thread#init(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String, long, java.security.AccessControlContext, boolean)
который будет оценивать и регистрировать следующее:
"**" + getName() + "**\n" + Arrays.toString(Thread.currentThread().getStackTrace())
Это выведет имя потока и способ создания потока (трассировка стека), который можно просто просмотреть.
При отладке приложения Eclipse вы можете остановить все потоки, щелкнув поле org.eclipse.equinox.launcher.Main в представлении отладки.
Затем оттуда для каждого потока вы можете увидеть трассировку стека и перейти к методу thred run.
Иногда это может помочь, а иногда нет.
Как сказал Брайан, хорошей практикой является именование потоков, потому что это единственный способ легко определить, "кто их создал"
К сожалению это не так. В Eclipse я вижу все блокирующие потоки, но их трассировки стека отражают только их внутреннее состояние и (по-видимому) не раскрывают информацию о месте их создания. Также из взгляда внутри объекта (используя представление Variables) я не смог выявить дальнейшие подсказки.