2016-08-15 6 views
5

基本的に、私はJVMによってロードされたすべてのクラスをリストするものを作成しようとしています。私が書いたものは動作しますが、それは動作しているjvmでのみ動作します。 私は別のJVMに動的に注入するJavaエージェントを作成しましたが、実際に注入する方法は実際には分かりませんでした。 このエージェントを別のJVMに実際に送信するにはどうすればよいですか? 可能ですか?Java - Javaエージェントを実行中のjvmに挿入する

答えて

-1

あなたが書いた内容を見ることなく支援を提供するのは難しいですが、これはjava.lang.instrumentパッケージのInstrumentation interface(public interface Instrumentation)という名前のクラスがJavaプログラミング言語コードを計測するのに必要なパッケージを提供していることを通知するだけです。

このクラスで提供されるこのようなメソッドの1つは、ロードされるすべてのクラスを含む配列を返すgetInitiatedClassesです。ドキュメントを

ルックhere

getInitiatedClasses

クラス[] getInitiatedClasses(クラスローダローダ)
はloaderが起動ローダーであるすべてのクラスの配列を返します。 ローダーがnullの場合、ブートストラップクラス ローダーによって開始されたクラスが返されます。

パラメータ:ローダー - 開始クラスリスト 戻り値が返されますローダー:

がない場合loaderが起動ローダー、長さゼロであるすべてのクラスを含む配列を
+0

私はこのことを認識しています。問題は、jarファイルがすでに実行されており、javaagentを接続する必要があることです。 – Stoud

3

HotSpot Attach APIで薬剤を注射することができる。
クラスパスに$JAVA_HOME/lib/tools.jarの次のスニペットを実行します。

VirtualMachine vm = VirtualMachine.attach(PID); 
    try { 
     vm.loadAgent(agentJar); 
    } finally { 
     vm.detach(); 
    } 

また、あなたは私のコマンドラインjattachユーティリティでこれを行うことがあります。

$ jattach PID load instrument false /path/to/agent.jar 

注添付ダイナミックサポートするために、あなたのJavaエージェントがagentmain方法とMANIFEST.MFAgent-Class性質を持っている必要があること。

+0

私はエージェントに少し問題があります。私は、インストゥルメンテーションエージェントをターゲットJVMとは別にパックするのが最も標準的な方法であると仮定しています。私の 'agentmain()'が呼び出されたとき、私は 'Class.forName(" pkg.name ")'を呼び出すことによってJVMクラスを見つけようとしましたが、常に 'NoClassDefFoundError'を返しています。私はここに質問を掲載しました(https://stackoverflow.com/questions/46523055/using-class-forname-in-java-instrumentation-agent?noredirect=1#comment80003396_46523055);ここにあります。私は、エージェントがVMに接続されていても、そのクラスを参照できない理由を少し混乱させます。 – ha9u63ar

6

ダイナミックエージェントは、ターゲットVM内のアタッチ時に実行されるagentmain(String, Instrumentation)メソッドを宣言する必要があります。 tools.jar(Java 9まで)依存関係は、JDKにのみ含まれていますが、JREには含まれていません。ただし、エージェントプログラムをJDKにバンドルしてそこからJVMにアタッチすることはできます。

最大の落とし穴は、異なるVMでAPIが異なることです。しかし、異なるVM用に異なる実装を含むbyte-buddy-agentのようなライブラリを使うことができます。これは、ID 私-IDでJavaプロセスにmy.jarに含まれているエージェントを添付

ByteBuddyAgent.attach("my.jar", "my-pid"); 

:添付ファイルをすることによって行うことでしょう。

+0

pidはtasklistで表示されるものと同じですか? – Stoud

+0

はい。 OSプロセスID。 –

+0

これを実行しようとしましたが、テストの結果、agentmainメソッドが呼び出されることはありません。 – Stoud

3

は、私の知る限りthe commentから理解として、あなたは別のJavaプロセス内からリモートJVMを検査することができます何かに興味を持っています。その場合は、JavaエージェントではなくServiceability Agentが必要です。

は、別のJVMプロセスに接続して、そのメモリを読み込み、VM構造を再構築し、リモートオブジェクトを反射的に検査することができます。ここで

は、リモートJVMによってロードされたすべてのクラスを一覧表示するためのサンプルツールです:

import sun.jvm.hotspot.runtime.VM; 
import sun.jvm.hotspot.tools.Tool; 

public class ListRemoteClasses extends Tool { 

    public static void main(String[] args) { 
     new ListRemoteClasses().execute(args); 
    } 

    @Override 
    public void run() { 
     VM.getVM().getSystemDictionary().classesDo(klass -> { 
      String className = klass.getName().asString().replace('/', '.'); 
      System.out.println(className); 
     }); 
    } 
} 

それを実行する方法:

java -cp $JAVA_HOME/lib/sa-jdi.jar:. ListRemoteClasses PID 
関連する問題