Ответ 1
Я предполагаю, что вы можете создать проблему с тем же запросом (набором запросов) в течение определенного периода времени. Хорошо, что вы определили MaxMetaspaceSize, иначе приложение будет использовать встроенную память, пока не закончится ее рост. Но я начну с следующих шагов:
- Проверьте, увеличивается ли количество загружаемых в JVM классов для одного и того же запроса, когда вы отправляете его на сервер несколько раз. Если да, возможно, вы создаете динамические классы, которые приведут к росту классов, загруженных в metaspace. Ну, как проверить количество загруженных классов, вы можете использовать visualvm для подключения к серверу с помощью JMX или запуска локально для имитации. Я расскажу о шагах для локальных, но для удаленного подключения JMX вы должны добавить следующее к параметрам JVM для приложения и запустить его и удаленно подключиться к порту 9999 и с помощью -XX: + UnlockDiagnosticVMOptions.
-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -XX:+UnlockDiagnosticVMOptions
Когда у вас есть visualvm (jvisualvm), подключенный к JVM, нажмите на монитор, а затем увидите количество загруженных классов. Там вы можете контролировать кучу, а также метапас. Но я добавлю другие инструменты для тщательного контроля метапас.
- Также, как только вы подключитесь к jvm, вы можете захотеть сделать снимок кучи и узнать классы, загруженные с помощью OQL. Поэтому перед тем, как вы берете кучу кучи, прекратите запросы на сервер, чтобы вы не попадали на любой запрос/исполняемый код и связанные с ним объекты, но это необязательно. Поэтому после запуска одного и того же набора запросов несколько раз внутри visualvm в "мониторе" щелкните "Дамп кучи" справа вверху. Затем откройте/загрузите моментальный снимок, и вы увидите опцию консоли OQL. вы увидите некоторые предопределенные запросы OQL на правой нижней панели в рамках анализа перменов. Запустите запрос с именем "гистограмма класса загружаемого класса", я думаю, что это даст количество классов, загружаемых каждым загрузчиком классов. Вы можете использовать его для определения того, какой класс загрузчик загружает классы.
выберите карту (sort (map (heap.objects('java.lang.ClassLoader'), '{loader: it, count: it.classes.elementCount}'), 'lhs.count < rhs.count '), 'toHtml (it) + "
" ')
Но запрос выше, который называется "classloader loaded class", будет медленным, который фактически покажет классы, загружаемые каждым загрузчиком классов.
select { loader: cl,
classes: filter(map(cl.classes.elementData, 'it'), 'it != null') }
from instanceof java.lang.ClassLoader cl
- Затем попытайтесь проследить рост в области метапасса. Теперь мы будем использовать jconsole и что-то новое, что java имеет: jmc (управление миссией java). Вы можете использовать jconsole для подключения к jvm (локальному или удаленному), и после того, как вы подключены, перейдите на вкладку памяти, и вы сможете отслеживать рост без кучи там, где должен быть кег метаданных и кеш и сжатое пространство класса. И теперь подключитесь
JMC
для подключения к виртуальной машине, а затем после подключения нажмите "Диагностические команды" в JMC, который находится справа. Поскольку мы включили UnlockDiagnosticVMOptions, GC.class_stats может быть выполнена. Вы можете запустить его с отображением всех столбцов и напечатать в csv. Таким образом, команда будет выглядеть так:
GC.class_stats -all=true -csv=true
И затем вы можете сравнить статистику по классам за разные периоды и выяснить, какие классы вызывают проблемы (рост метапроцесса) или какие классы имеют связанную информацию (данные метода/метода) в метапассе. Как анализировать выходы csv, собранные за время: ну, я бы взял этот csv и загрузил его в две аналогичные таблицы (представляющие csv) в базе данных или в другом месте для сравнения выходов csv GC.class_stats, где я могу запускать некоторый SQL или любые другие аналитические инструменты. Это даст лучшее представление о том, что именно растет в метапассе. Статистика GC-класса имеет следующие столбцы:
Index, супер, InstSize, InstCount, InstBytes, зеркало, KlassBytes, K_secondary_supers, VTab, Itab, OopMap, IK_methods, IK_method_ordering, IK_default_methods, IK_default_vtable_indices, IK_local_interfaces, IK_transitive_interfaces, IK_fields, IK_inner_classes, IK_signers, class_annotations, class_type_annotations, fields_annotations, fields_type_annotations, methods_annotations, methods_parameter_annotations, methods_type_annotations, methods_default_annotations, аннотации, Cp, CpTags, CpCache, CpOperands, CpRefMap, CpAll, MethodCount, MethodBytes, ConstMethod, MethodData, StackMap, байт-код, MethodAll, ROAll, RWAll, Всего, ИмяКласса, ClassLoader
Надеюсь, это поможет. Также кажется, что ошибка может быть в Java 8, если она не вызывает утечки в 1.7.
Кроме того, классы не будут выгружены из metaspace, если кто-либо держит любую ссылку на classloader. Если вы знаете, что ваши загрузчики классов должны быть GCed, и никто не должен содержать ссылку на ваш загрузчик классов, вы можете вернуться к дампу кучи в visualvm и щелкнуть экземпляр загрузчика класса и щелкнуть правой кнопкой мыши, чтобы найти "ближайший корень GC", который будет сообщать вы, кто держит ссылку на загрузчиков классов.