【问题标题】:Java Newbie: How to use Java Agent From the Command Line for InstrumentationJava 新手:如何从命令行使用 Java 代理进行检测
【发布时间】:2015-02-25 01:14:58
【问题描述】:

我正在尝试加载 Java 代理以使用 java.lang.instrument.Instrumentation 来测量对象的大小。这是我的 Java:

package com.example.memory.usage;

import java.lang.instrument.Instrumentation;
import java.util.*;


public class MemoryUsage {

    public static void main(String[] args) throws Exception {

        Random random = new Random();

        Set<Integer> integerSet = new HashSet<>();

        for(int i = 0; i < pixels; i++) {
            if(random.nextDouble() < 0.20) {
                integerSet.add(i);
            }
        }

        System.out.println(ObjectSizeFetcher.getObjectSize(integerSet));
    }

    public static class ObjectSizeFetcher {
        private static Instrumentation instrumentation;

        public static void premain(String args, Instrumentation inst) {
            System.out.println("Premain ... " + inst);
            instrumentation = inst;
        }

        public static long getObjectSize(Object o) {
            return instrumentation.getObjectSize(o);
        }
    }
}

由于这是一个 Maven 项目,这里是我的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>memory-usage</artifactId>
<version>1.0-SNAPSHOT</version>

<build>
    <finalName>memory-usage</finalName>
    <plugins>
        <!-- Compiler -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.0</version>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>

        <!-- Jar -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>com.example.memory.usage.MemoryUsage</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

        <!-- Assembly -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>attached</goal>
                    </goals>
                    <phase>package</phase>
                    <configuration>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                        <archive>
                            <manifest>
                                <mainClass>com.example.memory.usage.MemoryUsage</mainClass>
                            </manifest>
                            <manifestEntries>
                                <Premain-Class>java.lang.instrument.Instrumentation</Premain-Class>
                            </manifestEntries>
                        </archive>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
</project>

不,我不知道下一步该做什么。请帮忙。我跑了

$ mvn clean package

然后

$ java -jar target/memory-usage-jar-with-dependencies.jar

这给了我这个例外:

Exception in thread "main" java.lang.NullPointerException
    at com.example.memory.usage.MemoryUsage$ObjectSizeFetcher.getObjectSize(MemoryUsage.java:42)
    at com.example.memory.usage.MemoryUsage.main(MemoryUsage.java:29)

我应该怎么做才能运行它?

【问题讨论】:

    标签: java profiling instrumentation javassist javaagents


    【解决方案1】:

    启动机制被认为是 JVM/JRE 特定的。然而,package-summary of the instrumentation API 告诉你:

    命令行界面

    实现不需要提供从命令行界面启动代理的方法。在提供从命令行界面启动代理的方法的实现中,通过将此选项添加到命令行来启动代理:

    -javaagent:jarpath[=options]
    

    jarpath 是代理 JAR 文件的路径。 options 是代理选项。此开关可以在同一命令行上多次使用,从而创建多个代理。多个代理可以使用相同的 jarpath。代理 JAR 文件必须符合 JAR 文件规范。


    launcher documentation 也提供了提示:

    -javaagent:jarpath[=options]

    加载指定的 Java 编程语言代理。有关检测 Java 应用程序的更多信息,请参阅 Java API 文档中的 java.lang.instrument 包描述http://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html


    但请注意,您必须在清单中指定正确的代理类。据我所知,您将 java.lang.instrument.Instrumentation 指定为 premain 类,这是无稽之谈。在您的代码中,包含premain 方法的类是com.example.memory.usage.MemoryUsage$ObjectSizeFetcher,因此您应该指定该类...

    【讨论】:

    • 这是否让我更接近于实际分析对象的大小?
    • 当然可以。它告诉您如何确保在调用main 之前使用JVM 提供的Instrumentation 实例调用premain 方法。因此,您的字段将不再是 null。这就是你的问题所在。但如果你放弃了自己实现代理的想法,只需运行jvisualvm(甚至包含在 jdk 中)并让它完成工作......
    【解决方案2】:

    您静态调用getObjectSize。变量检测需要初始化(即instrumentation = new Instrumentation();)

    【讨论】:

    • 新仪器需要大量覆盖。加上它的暗示就是它通过public static void premain(String args, Instrumentation inst)
    • @DavidWilliams 我不认为 premain 被调用了。
    • 我认为你是对的,我在那里放了一个 `System.out.println 并没有看到任何东西。但这是以下在线示例。如果我创建一个新方法,getObjectSize 方法将被存根返回 0。显然我需要一个现有的实现,对吗?
    • 似乎可以通过 javaagent 从命令行执行此操作。你知道要这样做吗?我可以在哪里下载合适的代理来调整对象的大小?
    猜你喜欢
    • 2011-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-08
    • 1970-01-01
    • 1970-01-01
    • 2012-07-08
    相关资源
    最近更新 更多