阻止 java 程序打开线程
prevent java program from opening threads
我正在尝试 运行 一个 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 打开的线程? !
请注意,问题是如何防止用户线程而不是系统线程,我需要限制 运行ning 环境,就像我在第二个代码 "RLIMIT_NPROC" 中所做的那样
谢谢!
how can I prevent the threads opened in the java application but not those opened by the JVM ?
我不确定你能做到。阻止 JVM 创建线程就像说您想限制它创建的 String
的数量一样。如果代码创建了一个线程,那么您将无能为力。
唯一可能有用的是安全策略,但正如我所读,线程创建不受控制。参见 Java 的 docs on the permissions under control。
java.lang.OutOfMemoryError: Cannot create GC thread. Out of system resources.
您可能知道,除了 "main" 线程之外,Java 还会启动许多在后台工作的其他 JVM 特定线程。例如,一个简单的 main(String[] args)
程序启动 "main" 和我认为不包括 GC 线程的另外 5 个线程。内存管理和其他重要任务需要 JVM 线程。如果您将线程限制到 GC 线程无法启动的程度,那么 JVM 根本无法 运行。
<HACK>
您可以做的一件事是将线程数限制为精确的数量以包括系统线程和 "main"。在 main()
内部,在用户代码有机会启动更多线程之前,您可以使用 Thread.getAllStackTraces().size()
或然后设置 OS 限制来计算 运行ning 线程的数量到那个数字。如果仍然失败,则尝试将 1 或 2 添加到 size()
以说明堆栈跟踪图中未说明的其他后台线程。 </HACK>
综上所述,我的问题是您想要完成什么?如果您担心 Java 进程接管您的服务器,那么我想知道是否有 OS 设置可以更好地控制分配给该进程的系统资源数量。如何限制并发而不是线程数。也许寻找线程关联设置?然而,这将非常 OS 依赖。
这可以通过 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 and ThreadEnd events will help to count created threads. GetStackTrace 函数将有助于查找哪些 类 正在尝试创建线程。
我正在尝试 运行 一个 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 打开的线程? !
请注意,问题是如何防止用户线程而不是系统线程,我需要限制 运行ning 环境,就像我在第二个代码 "RLIMIT_NPROC" 中所做的那样
谢谢!
how can I prevent the threads opened in the java application but not those opened by the JVM ?
我不确定你能做到。阻止 JVM 创建线程就像说您想限制它创建的 String
的数量一样。如果代码创建了一个线程,那么您将无能为力。
唯一可能有用的是安全策略,但正如我所读,线程创建不受控制。参见 Java 的 docs on the permissions under control。
java.lang.OutOfMemoryError: Cannot create GC thread. Out of system resources.
您可能知道,除了 "main" 线程之外,Java 还会启动许多在后台工作的其他 JVM 特定线程。例如,一个简单的 main(String[] args)
程序启动 "main" 和我认为不包括 GC 线程的另外 5 个线程。内存管理和其他重要任务需要 JVM 线程。如果您将线程限制到 GC 线程无法启动的程度,那么 JVM 根本无法 运行。
<HACK>
您可以做的一件事是将线程数限制为精确的数量以包括系统线程和 "main"。在 main()
内部,在用户代码有机会启动更多线程之前,您可以使用 Thread.getAllStackTraces().size()
或然后设置 OS 限制来计算 运行ning 线程的数量到那个数字。如果仍然失败,则尝试将 1 或 2 添加到 size()
以说明堆栈跟踪图中未说明的其他后台线程。 </HACK>
综上所述,我的问题是您想要完成什么?如果您担心 Java 进程接管您的服务器,那么我想知道是否有 OS 设置可以更好地控制分配给该进程的系统资源数量。如何限制并发而不是线程数。也许寻找线程关联设置?然而,这将非常 OS 依赖。
这可以通过 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 and ThreadEnd events will help to count created threads. GetStackTrace 函数将有助于查找哪些 类 正在尝试创建线程。