From andy.fingerhut at gmail.com Sat Jul 6 17:55:50 2019 From: andy.fingerhut at gmail.com (Andy Fingerhut) Date: Sat, 6 Jul 2019 10:55:50 -0700 Subject: Should GraphLayout/parseInstance use IdentityHashMap for GraphPathRecord's? Message-ID: Thanks for developing JOL and making it so accurate! I've recently been building a little utility library in Clojure on top of it, primarily for learning about Clojure and JVM implementation details. https://github.com/jafingerhut/cljol I was looking through the implementation of the object graph walking in GraphLayout's parseInstance method, and realized that while it might not be terribly likely, the TreeMap named 'addresses' could have 'addresses.put()' called on it for the same address multiple times, if a GC happens during graph walking. To see if this was happening in a few local tests of my own, I made a change via the small diff that I will attempt to append to this message below. It turns out that one of the tests run via 'mvn package' caused the new exception to be thrown very consistently, unless changes are made to that test to force it to GC first. It seems that perhaps if 'addresses' was replaced with an IdentityHashMap that this problem could be avoided, since the key is the object's identity (even across GC moves), not whatever its current address happens to be. Would there perhaps be any interest in a patch like that? One down side is that it would change the API for those that use GraphLayout.parseInstance. Thanks, Andy Fingerhut In case it makes any difference, this patch is against the 0.9 version of JOL's source code, not the latest. diff -r 9a5fff552b23 jol-core/src/main/java/org/openjdk/jol/info/GraphLayout.java --- a/jol-core/src/main/java/org/openjdk/jol/info/GraphLayout.java Fri Sep 22 17:29:07 2017 +0200 +++ b/jol-core/src/main/java/org/openjdk/jol/info/GraphLayout.java Sat Jul 06 10:36:19 2019 -0700 @@ -106,6 +106,15 @@ private void addRecord(GraphPathRecord gpr) { long addr = gpr.address(); + if (addresses.containsKey(addr)) { + Object cur_val = addresses.get(addr); + Object new_val = gpr.obj(); + if (new_val != cur_val) { + String msg = "Internal error - GraphLayout.addRecord called with address " + addr + " object '" + new_val.getClass() + "' that is a duplicate of an object with '" + cur_val.getClass() + "' traversed earlier. Likely a GC occurred while walking an object graph."; + System.out.println(msg); + throw new IllegalArgumentException(msg); + } + } addresses.put(addr, gpr); Class klass = gpr.klass(); diff -r 9a5fff552b23 jol-core/src/test/java/org/openjdk/jol/info/ClassLayoutPrivatesTest.java --- a/jol-core/src/test/java/org/openjdk/jol/info/ClassLayoutPrivatesTest.java Fri Sep 22 17:29:07 2017 +0200 +++ b/jol-core/src/test/java/org/openjdk/jol/info/ClassLayoutPrivatesTest.java Sat Jul 06 10:36:19 2019 -0700 @@ -26,6 +26,17 @@ @Test public void testClass() { + System.gc(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + System.gc(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + System.gc(); GraphLayout.parseInstance(this.getClass()).toPrintable(); } From andy.fingerhut at gmail.com Fri Jul 12 08:24:18 2019 From: andy.fingerhut at gmail.com (Andy Fingerhut) Date: Fri, 12 Jul 2019 01:24:18 -0700 Subject: Should GraphLayout/parseInstance use IdentityHashMap for GraphPathRecord's? Message-ID: After sending my previous message, and experimenting a bit more with some possible changes, it was obvious that it is possible, and likely also preferable, to add new methods to the GraphLayout class, without affecting the existing API at all, other than by extending it with additional functionality. So, no breakage for any existing programs that use JOL, only additional methods that could be called if you want some different behavior. I have published one possible set of changes as diffs at the link below: https://github.com/jafingerhut/cljol/blob/master/doc/jol-dev-ideas/jol-0-9-plus-parseInstanceIds.diff The new method is: parseInstanceIds and it takes a second parameter of type Predicate that the caller can use to cause the GraphLayout walk to not follow references out of objects that the caller chooses, based on whatever criteria it wants. If you have chance to look at it, I would be curious if it might be of any interest for the official JOL code base, and if so, what kinds of changes would need to be made for it to be acceptable. Regards, Andy From akbar.bs at gmail.com Sat Jul 20 01:53:11 2019 From: akbar.bs at gmail.com (Akbar Bash) Date: Sat, 20 Jul 2019 07:23:11 +0530 Subject: Graphlayout fails in jetty/spring Message-ID: I am running a web app in jetty and trying to measure the size of one of the instances. When i tried from console I am getting the below warnings followed by classnotfound error # WARNING: Unable to get Instrumentation. Dynamic Attach failed. You may add this JAR as -javaagent manually, or supply -Djdk.attach.allowAttachSelf # WARNING: Unable to attach Serviceability Agent. Unable to attach even with module exceptions: [org.openjdk.jol.vm.sa.SASupportException: Sense failed., org.openjdk.jol.vm.sa.SASupportException: Sense failed., org.openjdk.jol.vm.sa.SASupportException: Sense failed.] java.lang.ClassNotFoundException: at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348) at org.openjdk.jol.util.ClassUtils.loadClass(ClassUtils.java:70) at org.openjdk.jol.operations.ClasspathedOperation.run(ClasspathedOperation.java:76) at org.openjdk.jol.Main.main(Main.java:60) I provided as javaagent library as part of the jetty startup configuration. When I used the GraphLayout API in the code. parseInstance() never returns. The instance is wired using Spring. Can you please let me know what should be the problem. Regards, Akbar