2

私はJavaアプリケーション、より具体的にはjarコンパイルされたものを実行しようとしています.Cでexecve()を使用し
ています.

char *cmd[] = {"a.jar"};
execve("a.jar",cmd,NULL);

それは問題なく動作していますが、このプログラムがそのようなものを使用して開くことができるスレッドの数を制限しようとすると:

struct rlimit rlp;
rlp.rlim_cur = rlp.rlim_max = limit_nproc; 
setrlimit(RLIMIT_NPROC,&rlp);

スレッドを開くJVMに問題があり、それを防止しているため、次のエラーが発生します。

java.lang.OutOfMemoryError: Cannot create GC thread. Out of system resources.

Javaアプリケーションで開かれたスレッドを防ぎ、JVMによって開かれたスレッドを防ぐにはどうすればよいですか? !

注意してください、問題はシステムスレッドではなくユーザースレッドを防ぐ方法です。2番目のコード「RLIMIT_NPROC」で行ったように、実行環境を制限する必要があります

ありがとう!

4

2 に答える 2

2

これは、 JVMTIエージェントで実現できます。

アイデアは、ネイティブ メソッドをインターセプトしThread.start0()、呼び出されるたびに例外をスローすることです。

C++ で記述されたサンプル エージェントを次に示します。

#include <jvmti.h>

// Original native implementation of Thread.start0(), if you wish to call it
extern "C" void JNICALL JVM_StartThread(JNIEnv* env, jthread thread);

void JNICALL StartThreadHook(JNIEnv* env, jthread thread) {
    env->ThrowNew(env->FindClass("java/lang/Error"), "Threads forbidden");
}

void JNICALL VMInit(jvmtiEnv* jvmti, JNIEnv* env, jthread thread) {
    // After VM is initialized, intercept Thread.start0() with our hook function
    jclass thread_class = env->FindClass("java/lang/Thread");
    JNINativeMethod start0 = {(char*)"start0", (char*)"()V", (void*)StartThreadHook};
    env->RegisterNatives(thread_class, &start0, 1);
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
    jvmtiEnv* jvmti;
    vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0);

    jvmtiEventCallbacks callbacks = {0};
    callbacks.VMInit = VMInit;
    jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
    jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);

    return 0;
}

エージェントをコンパイルします。

g++ -fPIC -shared -olibnothreads.so -Wl,-soname,libnothreads.so nothreads.cpp

エージェントを使用してアプリケーションを実行します。

java -agentpath:/path/to/libnothreads.so -jar app.jar

JVMTI を使用して、新しいスレッドの開始をいつ許可し、いつ拒否するかというカスタム ロジックを実装することもできます。たとえば、ThreadStartおよびThreadEndイベントは、作成されたスレッドをカウントするのに役立ちます。GetStackTrace関数は、スレッドを作成しようとしているクラスを見つけるのに役立ちます。

于 2016-06-09T01:03:50.310 に答える
0

Javaアプリケーションで開かれたスレッドを防ぎ、JVMによって開かれたスレッドを防ぐにはどうすればよいですか?

できるかどうかわかりません。JVM がスレッドを作成しないようにすることは、作成する の数を制限したいと言っているようなものですString。コードがスレッドを作成する場合、それに対してできることは何もありません。

役立つかもしれない唯一のことはセキュリティポリシーですが、私が読んだように、スレッドの作成は制御されていません. 制御下のアクセス許可については、 Java のドキュメントを参照してください。

java.lang.OutOfMemoryError: GC スレッドを作成できません。システム リソースが不足しています。

おそらくご存じのとおり、「メイン」スレッドに加えて、Java はバックグラウンドで動作する他の多くの JVM 固有のスレッドを開始します。たとえば、単純なmain(String[] args)プログラムは「メイン」と、私が信じているGCスレッドを含まない追加の5つのスレッドを開始します。JVM スレッドは、メモリ管理やその他の重要なタスクに必要です。GC スレッドが開始できないポイントまでスレッドを制限している場合、JVM はまったく実行できなくなります。

<HACK>できることの 1 つは、スレッドの数を正確な数に制限して、システム スレッドと「メイン」を含めることです。内でmain()、ユーザー コードがさらにスレッドを開始する機会を得る前に、 または を使用して実行中のスレッドの数をカウントし、Thread.getAllStackTraces().size()OS の制限をその数に設定できます。それでも失敗する場合size()は、スタック トレース マップで考慮されていない他のバックグラウンド スレッドを考慮して、 に 1 または 2 を追加してみてください。</HACK>

これはすべて言った、私が持っている質問は、あなたが達成しようとしていることです? Java プロセスがサーバーを乗っ取ることを心配しているなら、プロセスに与えられるシステム リソースの数を制御するのに適した OS 設定があるかどうか疑問に思います。スレッド数の代わりに同時実行数を制限するのはどうですか。スレッド アフィニティの設定を探してみてはいかがでしょうか。ただし、これは OS に大きく依存します。

于 2016-06-08T13:33:20.527 に答える