JOL object header information

Rafael Winterhalter rafael.wth at gmail.com
Thu Dec 18 22:59:31 UTC 2014


Brilliant, thanks. That took significantly less time than my glass fish
patch ;)

2014-12-18 23:48 GMT+01:00 Aleksey Shipilev <aleksey.shipilev at oracle.com>:
>
> Thank you, I have refactored this a bit, and committed:
>  https://bugs.openjdk.java.net/browse/CODETOOLS-7901220
>  http://hg.openjdk.java.net/code-tools/jol/rev/be8776814beb
>
> -Aleksey.
>
> On 12/19/2014 01:04 AM, Rafael Winterhalter wrote:
> > Hi all, sure thing. Find the patch attached. I signed the OCA a year ago
> > when I patched something for glassfish. If this is valid for JOL, great,
> > otherwise ping me.
> >
> > Index: jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java
> > IDEA additional info:
> > Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
> > <+>UTF-8
> > ===================================================================
> > --- jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java
> (revision 31:9a546334aa57fa0e114db159b2a8a5345c249b3e)
> > +++ jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java
> (revision 31+:9a546334aa57+)
> > @@ -35,13 +35,22 @@
> >  import javax.management.openmbean.CompositeDataSupport;
> >  import java.io.PrintWriter;
> >  import java.io.StringWriter;
> > +import java.io.InputStream;
> > +import java.io.File;
> > +import java.io.FileOutputStream;
> >  import java.lang.instrument.Instrumentation;
> >  import java.lang.management.ManagementFactory;
> >  import java.lang.reflect.Field;
> > +import java.net.URL;
> > +import java.net.URLClassLoader;
> >  import java.security.AccessController;
> >  import java.security.PrivilegedAction;
> >  import java.util.Arrays;
> >  import java.util.Random;
> > +import java.util.jar.Attributes;
> > +import java.util.jar.JarEntry;
> > +import java.util.jar.JarOutputStream;
> > +import java.util.jar.Manifest;
> >  import java.util.regex.Matcher;
> >  import java.util.regex.Pattern;
> >
> > @@ -55,6 +64,8 @@
> >
> >      private static Instrumentation INSTRUMENTATION;
> >
> > +    private static boolean installAttempt;
> > +
> >      public static final Unsafe U;
> >
> >      public static final String VM_NAME;
> > @@ -253,6 +264,7 @@
> >          private final boolean exactSizeAvail;
> >
> >          public SizeInfo(Object o, ClassLayout layout) {
> > +            VMSupport.installInstrumentation();
> >              exactSizeAvail = VMSupport.INSTRUMENTATION != null && o !=
> null;
> >              size = exactSizeAvail ? (int)
> VMSupport.INSTRUMENTATION.getObjectSize(o) : layout.instanceSize();
> >          }
> > @@ -418,6 +430,7 @@
> >      }
> >
> >      public static int sizeOf(Object o) {
> > +        installInstrumentation();
> >          if (VMSupport.INSTRUMENTATION != null) {
> >              return VMSupport.align((int)
> VMSupport.INSTRUMENTATION.getObjectSize(o));
> >          }
> > @@ -425,6 +438,79 @@
> >          return new
> CurrentLayouter().layout(ClassData.parseInstance(o)).instanceSize();
> >      }
> >
> > +    private static void installInstrumentation() {
> > +        if (!installAttempt) {
> > +            try {
> > +                doInstall();
> > +            } catch (Exception ignored) {
> > +            }
> > +        }
> > +    }
> > +
> > +    private static synchronized void doInstall() throws Exception {
> > +        if (installAttempt) {
> > +            return;
> > +        }
> > +        installAttempt = true;
> > +        ClassLoader classLoader = new URLClassLoader(new URL[]{new
> File(System.getProperty("java.home")
> > +                .replace('\\', '/') +
> "/../lib/tools.jar").toURI().toURL()}, null);
> > +        Class<?> virtualMachine =
> classLoader.loadClass("com.sun.tools.attach.VirtualMachine");
> > +        String runtimeName =
> ManagementFactory.getRuntimeMXBean().getName();
> > +        Object virtualMachineInstance =
> virtualMachine.getDeclaredMethod("attach", String.class)
> > +                .invoke(null, runtimeName.substring(0,
> runtimeName.indexOf('@')));
> > +        try {
> > +            File agentFile = File.createTempFile("jolAgent", ".jar");
> > +            try {
> > +                saveAgentJar(agentFile);
> > +                virtualMachine.getDeclaredMethod("loadAgent",
> String.class, String.class)
> > +                        .invoke(virtualMachineInstance,
> agentFile.getAbsolutePath(), "");
> > +                INSTRUMENTATION = doGetInstrumentation();
> > +            } finally {
> > +                agentFile.delete();
> > +            }
> > +        } finally {
> > +
> virtualMachine.getDeclaredMethod("detach").invoke(virtualMachineInstance);
> > +        }
> > +    }
> > +
> > +    private static Instrumentation doGetInstrumentation() {
> > +        try {
> > +            Field field = ClassLoader.getSystemClassLoader()
> > +                    .loadClass(Installer.class.getName())
> > +                    .getDeclaredField("instrumentation");
> > +            field.setAccessible(true);
> > +            return (Instrumentation) field.get(null);
> > +        } catch (Exception e) {
> > +            throw null;
> > +        }
> > +    }
> > +
> > +    private static void saveAgentJar(File agentFile) throws Exception {
> > +        InputStream inputStream =
> Installer.class.getResourceAsStream('/' +
> Installer.class.getName().replace('.', '/') + ".class");
> > +        if (inputStream == null) {
> > +            return;
> > +        }
> > +        try {
> > +            Manifest manifest = new Manifest();
> > +
> manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
> > +            manifest.getMainAttributes().put(new
> Attributes.Name("Agent-Class"), Installer.class.getName());
> > +            JarOutputStream jarOutputStream = new JarOutputStream(new
> FileOutputStream(agentFile), manifest);
> > +            try {
> > +                jarOutputStream.putNextEntry(new JarEntry('/' +
> Installer.class.getName().replace('.', '/') + ".class"));
> > +                byte[] buffer = new byte[1024];
> > +                int index;
> > +                while ((index = inputStream.read(buffer)) != -1) {
> > +                    jarOutputStream.write(buffer, 0, index);
> > +                }
> > +                jarOutputStream.closeEntry();
> > +            } finally {
> > +                jarOutputStream.close();
> > +            }
> > +        } finally {
> > +            inputStream.close();
> > +        }
> > +    }
> > +
> >      /**
> >       * Produces the toString string, only calling toString() on known
> types,
> >       * which do not mutate the instance.
> > @@ -526,6 +612,15 @@
> >
> >      static class MyDoubles4 {
> >          private double f1, f2, f3, f4;
> > +    }
> > +
> > +    public static class Installer {
> > +
> > +        private static volatile Instrumentation instrumentation;
> > +
> > +        public static void agentmain(String agentArgs, Instrumentation
> inst) {
> > +            instrumentation = inst;
> > +        }
> >      }
> >
> >  }
> >
> >
> >
> > 2014-12-18 21:02 GMT+01:00 Aleksey Shipilev <aleksey.shipilev at oracle.com
> > <mailto:aleksey.shipilev at oracle.com>>:
> >
> >     Hi Rafael, Serkan,
> >
> >     On 12/17/2014 05:41 PM, Rafael Winterhalter wrote:
> >     > But this other approach only works if VMSupport was loaded by the
> system
> >     > ClassLoader where agents must be loaded from. Otherwise, the
> VMSupport that
> >     > is the agent and the VMSupport that installs the agent are two
> different
> >     > classes and the set INSTRUMENTATION field would belong to a
> different
> >     > class. This is why I prefer the hack by adding an additional
> installer
> >     > class that is minimal in byte size and does not carry any other
> class
> >     > dependencies and inject this class. Also, I only access it by
> reflection in
> >     > order to avoid these class identity issues. Might not be as
> relevant for
> >     > JOL as I guess most people do not really use this from a servlet
> container
> >     > or somewhere but I guess there might be corner cases (?).
> >
> >     You will be suprised *where* people use JOL. Therefore, I would not
> like
> >     to artificially limit the its applicability.
> >
> >     I like Rafael's approach. Rafael, can you send the patch either in
> >     attachment or inline on this list? OpenJDK ToU requires us to accept
> the
> >     incoming changes on openjdk.java.net <http://openjdk.java.net>. You
> >     seem to already have the OCA
> >     signed, so we are in clear about attribution.
> >
> >     Thanks,
> >     -Aleksey.
> >
> >
>
>
>


More information about the jol-dev mailing list