JAVA_OPTS=-javaagent:[path/to/]jrebel.jar
or so -javaagent:/path-to/plumbr.jar
java.lang.instrument
) at runtime. This is if in brief. Official documentation can be read here , but it is rather scarce. Nothing is clear? So, let's understand. It is best to understand the examples. package ru.habrahabr.agent; public class Agent007 { public static void premain(String args) { System.out.println("Hello! I`m java agent"); } }
public static void premain(String args);
public static void premain(String args, Instrumentation inst);
MANIFEST.MF
, with the required attribute Manifest-Version: 1.0 PreMain-Class: ru.habrahabr.agent.Agent007
don't forget to add a newline to the end of the file jar -cvfm Agent007.jar manifest.mf ru/habrahabr/agent/Agent007.class
package ru.habrahabr.agent; public class AgentTester { public static void main(String[] args) { System.out.println("Hello! I`m agent tester"); } }
java -javaagent:Agent007.jar ru.habrahabr.agent.AgentTester Hello! I`m java agent Hello! I`m agent tester
-javaagent:jarpath[=options]
parameter -javaagent:jarpath[=options]
package ru.habrahabr.agent; import java.lang.instrument.Instrumentation; public class AgentCounter { public static void premain(String agentArgument, Instrumentation instrumentation) { System.out.println("Agent Counter"); instrumentation.addTransformer(new ClassTransformer()); } }
java.lang.instrument.ClassFileTransformer
interface and add your object via the Instrumentation.addTransformer
method package ru.habrahabr.agent; import java.lang.instrument.ClassFileTransformer; import java.security.ProtectionDomain; public class ClassTransformer implements ClassFileTransformer { private static int count = 0; @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { System.out.println("load class: " + className.replaceAll("/", ".")); System.out.println(String.format("loaded %s classes", ++count)); return classfileBuffer; } }
jar -cvfm agentCounter.jar manifest.mf ru/habrahabr/agent/AgentCounter.class ru/habrahabr/agent/ClassTransformer.class
package ru.habrahabr.agent; public class AgentTester { public static void main(String[] args) { A a = new A(); B b = new B(); C c = null; } } class A {}; class B {}; class C {};
java -javaagent:agentCounter.jar ru.habrahabr.agent.AgentTester Agent Counter load class: sun.launcher.LauncherHelper loaded 1 classes load class: ru.habrahabr.agent.AgentTester loaded 2 classes load class: ru.habrahabr.agent.A loaded 3 classes load class: ru.habrahabr.agent.B loaded 4 classes
results may vary for different versions of java sun.reflect.GeneratedMethodAccessor230 loaded 33597 classes java.rmi.server.Unreferenced loaded 33598 classes
Instrumentation
interface there is a remarkable long getObjectSize(Object objectToSize)
that returns the size of the object. But how to get access to the agent from our application? And we don’t have to do anything special, the javaagent is automatically added to the classpath and all we have to do is add an instrumentation instrumentation field to the agent and initialize it in the premain method. package ru.habrahabr.agent; import java.lang.instrument.Instrumentation; public class AgentMemoryCounter { private static Instrumentation instrumentation; public static void premain(String args, Instrumentation instrumentation) { AgentMemoryCounter.instrumentation = instrumentation; } public static long getSize(Object obj) { if (instrumentation == null) { throw new IllegalStateException("Agent not initialised"); } return instrumentation.getObjectSize(obj); } }
AgentMemoryCounter.getSize(obj)
method from an application class. package ru.habrahabr.agent; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Calendar; public class AgentTester { public static void main(String[] args) { printObjectSize(new Object()); printObjectSize(new A()); printObjectSize(1); printObjectSize("string"); printObjectSize(Calendar.getInstance()); printObjectSize(new BigDecimal("999999999999999.999")); printObjectSize(new ArrayList<String>()); printObjectSize(new Integer[100]); } public static void printObjectSize(Object obj) { System.out.println(String.format("%s, size=%s", obj.getClass() .getSimpleName(), AgentMemoryCounter.getSize(obj))); } } class A { Integer id; String name; }
java -javaagent:agentMemoryCounter.jar ru.habrahabr.agent.AgentTester Agent Counter Object, size=8 A, size=16 Integer, size=16 String, size=24 GregorianCalendar, size=112 BigDecimal, size=32 ArrayList, size=24 Integer[], size=416
getObjectSize()
method does not take into account the size of the nested objects, that is, only the memory spent on the object reference is taken into account.Source: https://habr.com/ru/post/230239/
All Articles