1

I'd like to build an OQL query with which to recursively print out all the static data of a JVM heap dump from classes within a specific package. I'm aware that there are potentially lots of issues in going recursively through memory references, but (at least initially) I'll mitigate them by thresholding the depth.

As per the documentation, classes have a statics field, which in turn should be composed of names and values:

statics - name, value pairs for static fields of the Class.

I've come to a halt in obtaining the name of each of these static fields by using the field.name expression and don't know how to iterate an object's non-static fields. I currently have:

select map(
    filter(
        filter(heap.classes(), "/com.heap./.test(it.name)"),
        function (clazz) {
            if (clazz.statics) {
                return true;
            }
            return false;
        }
    ), function (clazz) {
        var res = '';
        res += toHtml(clazz.name) + " : " + toHtml(clazz.statics) + "<br>";
        map(clazz.statics, function (field) {
            res += "--" + toHtml(field) + "," + toHtml(field.name) + "," + toHtml(field.state) +"<br>";
        });
        return res + "<br>";
    }
)

And get the following output:

com.heap.dump.DataHolder : { :sun.misc.Launcher$AppClassLoader#1, }
--sun.misc.Launcher$AppClassLoader#1,null,null

com.heap.dump.HeapDumperTest : { dataHolder:com.heap.dump.DataHolder#1, mutableStaticState:java.lang.String#225, :sun.misc.Launcher$AppClassLoader#1, }
--com.heap.dump.DataHolder#1,null,java.lang.String#224
--java.lang.String#225,null,null
--sun.misc.Launcher$AppClassLoader#1,null,null

com.heap.dump.Main : { :sun.misc.Launcher$AppClassLoader#1, }
--sun.misc.Launcher$AppClassLoader#1,null,null

I'm iterating the clazz.statics using the map() function, following this answer.

It looks like the field argument is just the field's value, as field.name is always null and field.state actually retrieves the field on one of the objects (com.heap.dump.DataHolder.state).

Main questions:

  • While iterating static fields, how can the field name, aside from the value, be obtained?
  • Once I have an object/instance I want to traverse, how do I iterate the non-static fields (name and value) for that object? This way of obtaining a field's value, just like is the field.state statement, looks helpful only if I already know the field names, which is not the case here.

Additional questions:

  • How do I filter out the empty-named AppClassLoader static fields?
  • Am I using the wrong tool for the job? Is there an easier alternative to VisualVM's OQL?
clausavram
  • 546
  • 8
  • 14

1 Answers1

2

statics is a map, so you should use for(..) to iterate it. I updated your query. See below:

select map(
    filter(
        filter(heap.classes(), "/com.heap./.test(it.name)"),
        function (clazz) {
            if (clazz.statics) {
                return true;
            }
            return false;
        }
    ), function (clazz) {
        var res = '';
        res += toHtml(clazz.name) + " :<br>";
        for (field in clazz.statics) {
            res += "-- " + toHtml(field) + ", " + toHtml(clazz.statics[field]) +"<br>";
        }
        return res + "<br>";
    }
)
Tomas Hurka
  • 6,723
  • 29
  • 38
  • Your answer doesn't address the second main question, namely how to start iterating and iterating over each individual field's sub-fields. But it is very helpful nonetheless, thank you! – clausavram Feb 14 '20 at 15:41