Исследуйте секретный OQL в куче

Java
Исследуйте секретный OQL в куче

предисловие

Откровенно говоря, это что-то вроде вечеринки с заголовками, ощущение шага в науку, на самом деле, это поделиться с вами оOQLкакой-то контент.

OQLчто это такое?

Это язык объектных запросов, основанный на снапшотах в куче java, его синтаксис похож на наш обычный SQL, HQL и т. д., в конце концовQLсемья.

По характеристикам запроса в его куче, естественно, можно провести диагностику памяти, или сгенерировать нужный отчет и т.д.

я сам предпочитаю использоватьOQL, в конце концов, возможность писать код самостоятельно — это достаточно гибко, а гибкость, естественно, является фактором, привлекающим внимание людей.

Вторая причина, естественно:

Сегодня, от введения до фактического примера, неясно, чтоOQL"Друг мой, есть еще один способ отладки.

Как сказано в «Глубоком понимании виртуальной машины Java»: «Ни один инструмент не является« секретным оружием », и если он у вас есть, вы можете« вылечить все болезни »». Так что еще один навык — это просто еще одна идея отладки.

текст

Если вы настаиваете на прочтении текста, я думаю, вы понимаетеheap dumpчто это такое,

такструктура памятиТакие понятия вводятся не слишком много в этой статье.

heap dumpСуществует множество инструментов анализа, от JConsole до Jhat, и широко используемый MAT, их встроенные функции уже очень мощные, и их можно написать самостоятельно.OQL?

Это легко понять, смотреть на Report и писать SQL, естественно, не одно и то же, первое — результат концентрации на конкретной области, а второе — гибкий язык разработки.

Начнем с простого примера, а позже я буду использовать классическую «Эффективную Java» в «Эффективной Java».возможная утечка памяти"Пример кода, показывающий, как писать"интересный OQL".

простой пример

Первый шаг, безусловно,heap dump, так как это первоепростой пример, вы можете найти любойheap dumpНачать.

Tip: Инструментальные привычки у всех разные. Сегодняшние операции автора, такие как дамп кучи, чтение файлов hprof и выполнениеOQL, все вjVisualVmосуществляется в.

Если вы опытный любитель марихуаны, конечно, вы можете пропустить простой пример и продолжить чтение следующего содержания~

Сначала начните со списка слевасчастливый процессВозьмите средство просмотра из середины, выполните дамп кучи и убедитесь, что имя должно быть внутренним процессом в IDEA, который запускает автор.

Неудивительно, что он перейдет на страницу анализа heapDump, другие функции будут временно пропущены, выберите в раскрывающемся списке в верхнем левом углу сегодняшнюю тему.OQL Console".

Запросите все «экземпляры строк», которые можно рассматривать какOQL"привет мир" в . Эта статья не исключение:

select 
  s
from 
  java.lang.String s

Напишите вышеуказанный OQL в текстовое поле ниже

Как видно из рисунка выше, все экземпляры String выведены, ничем не отличается от обычных средств визуализации БД?

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

Здесь тоже есть небольшая деталь, на самом деле в OQL тоже есть диалект, но он ограничен разными запущенными инструментами.

Например, в некоторых книгахselect * from java.lang.StringВ качестве первого вводного заявления,

Но в моем нынешнемvisualVM2.0Он сообщит об ошибке при работе в середине и будет нормально выводиться в MAT.

Хотя общая грамматика та же, детали должны основываться на грамматике, представленной на официальном сайте инструмента, который вы привыкли использовать.

Пример в эффективной Java

Если вы читали «Эффективную Java», вы должны помнить классический фрагмент кода, демонстрирующий сценарий, в котором существует риск утечки памяти.

Неважно, если вы его не читали, этот код очень прост, и я также вставил его сюда:

class Stack {
        private Object[] elements;
        private int size = 0;
        private static final int DEFAULT_INITIAL_CAPACITY = 16;

        public Stack() {
            elements = new Object[DEFAULT_INITIAL_CAPACITY];
        }

        public void push(Object e) {
            ensureCapacity();
            elements[size++] = e;
        }

        public Object pop() {
            if (size == 0) {
                throw new EmptyStackException();
            }
            return elements[--size];
        }

        /**
         * Ensure space for at least one more element, roughly
         * doubling the capacity each time the array needs to grow.
         */
        private void ensureCapacity() {
            if (elements.length == size) {
                elements = Arrays.copyOf(elements, 2 * size + 1);
            }
        }
    }

Код очень простой, самореализующийся стек, операция pop забывает удалить ссылку в массиве элементов, и есть риск утечки памяти.

Затем я буду использовать этот код в качестве демонстрации, чтобы увидетьOQLможет сделать что-нибудь.

автортестовый код:

public static void main(String[] args) throws Exception {
        // stack1
        Stack stack1 = new Stack();
        // stack1入栈30个元素
        addItem(stack1);
        // stack2
        Stack stack2 = new Stack();
        // stack2入栈30个元素
        addItem(stack2);
        // stack2出栈20元素
        for (int i = 0; i < 20; i++) {
            stack2.pop();
        }
        System.out.println("----Over----");
        // 通知full gc, 如果jvm心情不错,可以拿到dump
        System.gc();
        Thread.sleep(5000);
}

Авторский тест очень прост: два из вышеперечисленных стеков инстанцируются, один не имеет операции извлечения, другой имеет операцию извлечения и экземпляр операции извлечения, который, естественно, сохраняет ссылки с истекшим сроком действия.

Чтобы получить файл дампа, я добавил следующие два параметра запуска:

  • -XX:+HeapDumpBeforeFullGC
  • -XX:HeapDumpPath=/Users/vt/logs/jvm

То есть дамп перед FullGC.

Давайте посмотрим, что можно сделать с помощью OQL? Чтобы опустить пробел в следующем содержимом, OQL и результаты вывода представлены словами Input и Output.

Вход:

select 
  s.elements.length
from instanceof 
  com.vt.example.LeakTest$Stack s

Выход:

33
33

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

Поскольку вывод результата поддерживает формат json, мы могли бы запросить еще какой-нибудь контент.

Вход:

 select 
  {
    "elements's length" :s.elements.length, 
    "instance": s, 
    "size attr" : s.size, 
    "count" : (actualCount = count(filter(s.elements, "it != null")))
  }
from instanceof 
  com.vt.example.LeakTest$Stack s

Выход:

{
instance = com.vt.example.LeakTest$Stack#1,
count = 30,
size attr = 30,
elements's length = 33
}

{
instance = com.vt.example.LeakTest$Stack#2,
count = 30,
size attr = 10,
elements's length = 33
}

Приведенный выше оператор OQL автора запрашивает адрес экземпляра, атрибут размера экземпляра, длину контейнера массива в экземпляре иреальный размер.

Реальный размер считается в контейнере массиване нольЭлементы.

То есть упомянутая выше проблема со стеком заключается в том, что для элемента с истекшим сроком действия не устанавливается значение null при извлечении из стека, что приводит к риску утечки памяти.

Итак, взгляните на приведенные выше результаты OQL, знаете ли вы что-нибудь?

Правильно, это элемент, фактически сохраненный вторым экземпляром, который не соответствует размеру атрибута size.Естественно, это экземпляр, в котором возникла проблема.

Но не все так однозначно, давайте оптимизируем другую версию, чтобы посмотреть как:

Вход:

select 
  {
    "实例中数组容器当前大小" :s.elements.length, 
    "实例地址": s, 
    "当前size属性" : s.size, 
    "实际保存的引用数量" : (actualCount = count(filter(s.elements, "it != null"))),
    "疑似泄漏" : (actualCount > s.size) ? "<font color='red'>有</font>" : "无" 
  }
from instanceof 
  com.vt.example.LeakTest$Stack s

Выход:

Последняя версия описана на китайском, и текст выделен.Так понятнее?

При использовании OQL для непосредственного поиска нужного нам отчета может оказаться невозможным полагаться на базовые функции.

наконец

Увидев это, каждый должен иметь предварительное представление об OQL и о том, как просто «играть», и на этом статья окончена.

На практике OQL выше не обнаруживает утечки памяти.Контент в основном предназначен для демонстрационных функций, что дает новый набор идей читателям, которые не понимают OQL, но это не решение~