barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)
Показаны сообщения с ярлыком hprof. Показать все сообщения
Показаны сообщения с ярлыком hprof. Показать все сообщения

пятница, 21 октября 2016 г.

Java: Выгрузка в файлы бинарных массивов из хип-дампа

Задача

Выгрузить в файлы все бинарные массивы с объемом больше 10Мб из хип-дампа.

Решение

OQL-скрипт:

var i = 0;
map(
  heap.objects('byte[]', false, 'sizeof(it)>10000000'),
  function(v) {
    var file = new java.io.FileOutputStream("T:/binaries/"+i+".bin");
    try {    
      for(var j=0;j<v.length;j++) {
        file.write(v[j]);
        file.flush();
      }
    } finally {
      file.close();
    }
    i++;
    return v;
  }
);
А вообще, экспортировать массивы байт в файл умеет Netbeans, правда, только по одному массиву за раз. Для этого необходимо выделить нужный массив в списке экземпляров, и нажать "Сохранить в файл" под окошком с заголовком "Элементы массива". В качестве выходного формата поддерживается как csv, так и bin (последний наиболее удобен, если нас интересует непосредственно бинарный контент, а не элементы массива байт по-отдельности). И, кстати, экспорт в файл Natbeans делает на пару порядков быстрее, чем приведенный выше скрипт.

четверг, 20 октября 2016 г.

OQL: запись данных из хип-дампа в файл

Бывают ситуации, когда средств OQL недостаточно для проведения требующегося анализа хип-дампа, и проще выгрузить нужные данные в файл и проанализировать их внешним инструментом. 
К примеру, столкнулся со следующей задачей: есть некий класс со строковым полем. В хип-дампе около 10 миллионов объектов данного класса, и нужно по ним собрать статистику, какое значение данного строкового поля встречается сколько раз. В OQL нет аналога SQL-ного GROUP BY, поэтому, поломав голову над реализацией группировки с применением комбинаций map / sort / filter и упершись в то, что полученное решение работает крайне медленно, я решил выгрузить все строки в файл, и потом уже обработать этот файл каким-нибудь более удобным, чем OQL, инструментом.
Например, следующий код выведет в файл namespaces.log пространства имен родительских элементов всех объектов класса OMTextImpl:
var file = new java.io.FileWriter("T:/namespaces.log");
unique(map(
  heap.objects('org.apache.axiom.om.impl.llom.OMTextImpl'),
  function(v) {
    var ns = v.parent == null ? "null_parent" :(v.parent.ns == null ? "null_ns" : (v.parent.ns.uri == null ? "null_uri" : v.parent.ns.uri));
    file.write(new java.lang.String(ns.toString() + "\r\n"));
    file.flush();
    return "1";
  }
));
А такой код - локальные имена всех объектов OMElementImpl:
var file = new java.io.FileWriter("T:/omelements.log");
unique(map(
  heap.objects('org.apache.axiom.om.impl.llom.OMElementImpl'),
  function(v) {
    file.write(new java.lang.String(v.localName));
    file.write(new java.lang.String("\r\n"));
    file.flush();
    return "1";
  }
)); 
Зачем нужен unique и return "1": дело в том, что, по крайней мере, Netbeans считает, что если OQL вернул 100 объектов, нужно прекратить итерацию, вывести эти 100 объектов пользователю и написать, что, де, "слишком много результатов, уточните запрос".  Т.е. если из запросов выше убрать unique, в файл будут записаны значения только из первых 100 найденных объектов заданного класса. Использование же unique заставит OQL-движок продолжать итерации, пока не будет найдено 100 уникальных значений, а т.к. map-функция всегда возвращает константу "1", это эквивалентно итерации по абсолютно всем объектам.
PS Хорошая справка по OQL: http://visualvm.java.net/oqlhelp.html