JOL object header information
Rafael Winterhalter
rafael.wth at gmail.com
Thu Dec 18 22:04:07 UTC 2014
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>:
>
> 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. 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