0

My question is rather short and compact:

If I find two objects with VisualVM, what kind of OQL query can I perform to find all objects that have (indirect) reachables or references to these two objects?

Update for JB:

After editing your code, I came up with the following:

//QUERY SCRIPT: find object that (indirectly) references to all target objects
    //list all objects that the objects we search for should (indirectly) refer to
    var targetObjects =     [   heap.findObject("811819664"), //eg. obj that contains a player's health
                    heap.findObject("811820024") //eg. obj that contains the same player's name
                ];

    //list all objects here that every or most objects have as an indirect referer (eg. base class loaders)
    var ignoreReferers =    []; //eg. [heap.findObject("ignId1")];

    //set array with all elements that refer to each target object
    var targetObjectsReferers = [];
    for (var tarObjIndex in targetObjects) {
        var targetObjRefElements = [];

        //get the live path of this target object
        var livePaths = heap.livepaths(targetObjects[tarObjIndex]);

        //cleanup every live path
        for (var livePathsIndex in livePaths) {
            var curLivePath = livePaths[livePathsIndex];
            if ((curLivePath == null) || (curLivePath == "undefined")) continue;

            //remove last element from live path as it is the actual object
            curLivePath.pop();

            //remove elements that equal an ignore referer object
            for (var pathElementIndex in curLivePath) {
            if ((curLivePath[pathElementIndex] == null) || (curLivePath[pathElementIndex] == "undefined")) continue;

                for (var ignoreIndex in ignoreReferers) {
                    if (identical(curLivePath[pathElementIndex], ignoreReferers[ignoreIndex])) curLivePath.splice(pathElementIndex, 1); //FIXME: this might fail if index is not updated
                }
            }       
        }

        //merge remaining life paths elements into targetObjRefElements
        for (var livePathsIndex in livePaths) {
            var curLivePath = livePaths[livePathsIndex];

            for (var curLivePathIndex in curLivePath) {
                targetObjRefElements.push(curLivePath[curLivePathIndex]);
            }
        }

        //remove duplicate referers
        targetObjRefElements = unique(targetObjRefElements, 'objectid(it)');

        //add to target objects referers
        targetObjectsReferers.push(targetObjRefElements);
    }

    //filter and return
    filter(targetObjectsReferers[0], function(it1) {
        var rslt = contains(targetObjectsReferers[1], function(it2) { //FIXME: this limits it to 2 objects!
            return identical(it1, it2);
        });
        return rslt;
    });

This returns a pop is not defined error after a while, which I am trying to resolve. If I manage to resolve that I can see if it provides the expected results.

Tom
  • 8,536
  • 31
  • 133
  • 232

1 Answers1

3

It sounds like you are trying to get all reference chains keeping your objects alive. You can use heap.livepaths(object) function to obtain them. You can take some hints from the following code

var paths1 = heap.livepaths(heap.findObject("1684177040")) // use the objectid of the first instance
var paths2 = heap.livepaths(heap.findObject("1684177160")) // use the objectid of the second instance

var pathArr1 = unique(rcs2array(paths1), 'objectid(it)') // flatten all the livepaths to a single array of instances
var pathArr2 = unique(rcs2array(paths2), 'objectid(it)') // the same for the second instance

// calculate the arrays' intersection - the result is the set of object keeping both of your instances alive
filter(pathArr1, function(it1) { 
  var rslt = contains(pathArr2, function(it2) {
     return (objectid(it1) == objectid(it2))
  })
  return rslt
})

// helper function to convert an array of reference chains to a flat array of objects
function rcs2array(rcs) {
  var arr = new Array()

  for(var i=0;i<rcs.length;i++) {
    var rc = rcs[i];
    for(var j=0;j<rc.length;j++) {
        arr.push(rc[j])
    }
  }
  return arr
}

Please, bear in mind that this works only in VisualVM and jhat

JB-
  • 2,615
  • 18
  • 17
  • I have been trying to get something similar working. How do you actually select the results of the filter in visualVM? It does not seem to be possible for me to add code outside of the select statement? – Tom Feb 18 '11 at 13:41
  • I have updated my original question with the code I came up with. Maybe yours makes more sense, but shouldn't you check every object for the references? And how do you execute code befor the select statement? – Tom Feb 18 '11 at 13:46
  • @Tom 1. You can omit the select completely if you decide to go the way of complex JS logic. In case you don't use the "select a from java.lang.Object a" form the OQL engine takes the last script statement as the desired result. 2. I don't understand what you mean by "check every object for references". Can you elaborate, please? – JB- Feb 18 '11 at 15:50
  • thanks. Please ignore that statement, I understand your logic now (mine did not make any sense at all actually). I updated my question again with my current version (thanks to your answer). It has some flaw which I am trying to resolve.. will update when I get the expected results or not. – Tom Feb 18 '11 at 15:54
  • May I ask you where you learnt about OQL syntax in jVisualVM? I could not find a comprehensive documentation (https://visualvm.java.net/oqlhelp.html is rather concise). Thanks! – Matthieu May 02 '17 at 16:21
  • 1
    Actually, I ported the jhat OQL to VisualVM. So, by inspecting the source code. The OQL help covers all the standard parts of OQL, what you can see in this example is pure JS which is using helper functions to inspect heap dump contents. – JB- May 09 '17 at 12:32