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 打开的线程?!

请注意,问题是如何防止用户线程而不是系统线程,我需要对运行环境进行限制,就像我在第二个代码“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 来实现自定义逻辑,何时允许以及何时拒绝启动新线程。例如,ThreadStartThreadEnd事件将有助于计算创建的线程。GetStackTrace函数将帮助找出哪些类正在尝试创建线程。

于 2016-06-09T01:03:50.310 回答
0

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

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

唯一可能有帮助的是安全策略,但是当我阅读它时,线程创建不受控制。有关受控制的权限,请参阅 Java 的文档。

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

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

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

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

于 2016-06-08T13:33:20.527 回答