我正在尝试运行一个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 打开的线程? !
请注意,问题是如何阻止用户线程而不是系统线程,我需要对运行环境进行限制,就像我在第二个代码“RLIMIT_NPROC”中所做的那样
谢谢!
最佳答案
这可以通过 JVMTI 来实现代理。
这个想法是拦截 native 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函数将有助于查找哪些类正在尝试创建线程。
关于java - 阻止java程序打开线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37701164/