JOL object header information
Aleksey Shipilev
aleksey.shipilev at oracle.com
Thu Dec 18 22:48:57 UTC 2014
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