防止java程序打开线程

防止java程序打开线程,java,multithreading,jvm,execve,setrlimit,Java,Multithreading,Jvm,Execve,Setrlimit,我正在尝试使用c中的execve()运行一个java应用程序,更具体地说是一个jar编译的应用程序 诸如此类: char *cmd[] = {"a.jar"}; execve("a.jar",cmd,NULL); struct rlimit rlp; rlp.rlim_cur = rlp.rlim_max = limit_nproc; setrlimit(RLIMIT_NPROC,&rlp); 这是正常的,但当我试图限制该程序可以使用以下方式打开的线程数时: char *cmd[]

我正在尝试使用c中的execve()运行一个java应用程序,更具体地说是一个jar编译的应用程序 诸如此类:

char *cmd[] = {"a.jar"};
execve("a.jar",cmd,NULL);
struct rlimit rlp;
rlp.rlim_cur = rlp.rlim_max = limit_nproc; 
setrlimit(RLIMIT_NPROC,&rlp);
这是正常的,但当我试图限制该程序可以使用以下方式打开的线程数时:

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”中所做的那样

谢谢

如何防止java应用程序中打开的线程而不是JVM打开的线程

我不确定你能不能。阻止JVM创建线程就像说要限制它创建的
String
s的数量。如果代码创建了一个线程,那么您对此无能为力

唯一可能有用的是安全策略,但正如我所读到的,线程创建是不受控制的。参见Java的

java.lang.OutOfMemoryError:无法创建GC线程。系统外资源

正如您可能知道的,除了“主”线程外,Java还启动了许多其他在后台工作的JVM特定线程。例如,一个简单的
main(String[]args)
程序启动“main”,并为我添加了5个线程,其中不包括我认为的GC线程。JVM线程用于内存管理和其他重要任务。如果将线程限制到GC线程无法启动的程度,那么JVM将根本无法运行

您可以做的一件事是将线程数限制为包含系统线程和“main”的精确数目。在
main()
内部,在用户代码有机会启动更多线程之前,您可以使用
Thread.getAllStackTraces().size()
计算正在运行的线程数,然后将操作系统限制设置为该数。如果此操作仍然失败,请尝试向
size()
添加1或2,以说明堆栈跟踪映射中未说明的其他后台线程<代码>

所有这些都说明了,我的问题是你想要实现什么?如果您担心Java进程会接管您的服务器,那么我想知道是否有操作系统设置可以更好地控制为该进程提供了多少系统资源。限制并发性而不是线程数量如何。也许可以查找线程关联设置?这将非常依赖于操作系统。

这可以通过代理实现

其思想是拦截本机
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实现何时允许和何时拒绝启动新线程的自定义逻辑。例如,和事件将有助于计算创建的线程数。函数将帮助查找哪些类正在尝试创建线程

如果没有参数可以传递给java代码来控制创建的线程数量,那么如果您通过某种外部方式禁止创建线程,那么代码很可能无法正常工作。在所有线程API都没有声明或记录启动线程失败的异常情况之后。@AliKanaan,如果我编写了一个需要执行X的程序,而您在一个阻止它执行X的环境中运行该程序,那么该程序将无法在该环境中正常运行。它不会“起作用”。如果我写了一个程序,当Y可用时可以利用Y,但当Y不可用时,它的设计是以不同的方式解决问题,那么情况就不同了。这完全取决于程序是如何编写的。如果程序是一个服务器,而环境阻止它启动它的“接受”线程,那么它将不会提供任何请求。你误解了我的意思。我并不否认setrlimit()是有用的。我的意思是,你不能对任何程序强加任意的限制,并期望程序能正常工作。我可以设计一个使用尽可能多线程的程序。我可以设计另一个程序,通过创建四个线程来解决不同的问题。如果您尝试在一个将每个程序限制为三个线程的环境中运行这两个程序,那么第一个程序将适应该限制并按预期运行,但第二个程序将失败。感谢gray的回复,我认为您的建议是一种黑客行为,但面临着一个问题,需要深入思考,如果运行JVM和主类所需的进程数量可能相差2个线程,或者在两个不同代码的两次不同运行之间相差1个线程,该怎么办;但是,如果不同版本之间的线程的精确数量不同怎么办!:\??!!是否保证此线程数不会改变!不幸的是,不能保证@alikanan在不同的Java版本之间运行,但是使用相同JVM版本到main的不同运行应该产生相同数量的系统线程。我不认为有变化,但我不是100%肯定。因此,黑客。祝你好运。我想知道你是否能通过groovy中的元编程实现同样的目标。这将是一个有趣的练习,但仍然。。我看不到你提供给JVMTI代理的链接,我可能在一个禁止该网站的国家,所以我会使用你提供的示例,如果你能给我其他有用的示例,我会很高兴,非常感谢这真的很有用:)@alikanan该链接基本上指向JVM工具Interf