linux上的JNI_CreateJavaVM是否会破坏堆栈?

时间:2011-08-22 20:25:17

标签: linux jvm stack java-native-interface

这发生在带有64位应用程序的linux 2.6.18-238.5.1.el5上。我的进程堆栈大小是10MB。但是,在(成功)调用JNI_CreateJavaVM后,我似乎只剩下1-2 MB的堆栈。如果我越过它 - 我得到了内存故障,好像我在堆栈中溢出。

一些注意事项:

  1. 如果我不创建JVM,那么我可以访问整个我的10MB堆栈。
  2. 使用相同makefile的相同测试程序在Solaris上运行正常,即使调用JVM
  3. 也是如此

    测试来源:

    #include <jni.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    void CreateVM(JavaVM ** jvm) {
    
        JNIEnv *env;
        JavaVMInitArgs vm_args;
        JavaVMOption options[1];
        options[0].optionString = (char*)"-Xcheck:jni";
    
        vm_args.version = JNI_VERSION_1_6;
        vm_args.nOptions = 0;
        vm_args.options = options;
        vm_args.ignoreUnrecognized = 0;
    
        int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);
        if(ret < 0) {
            printf("\nUnable to Launch JVM\n");
            exit(1);
        }
    
        if ( env->ExceptionCheck() == JNI_TRUE ) {
            printf("exception\n");
            exit(1);
        }
    }
    
    void f() {
        printf("inside...\n");
        //eat up a few megs of stack
        char stackTest[0x2FFFFF];
        printf("...returning");
    }
    
    int main(int argc, char* argv[]) {
        JavaVM * jvm;
        CreateVM(&jvm);
    
        f();
    
        printf("exiting...\n");
        return 0;
    }
    

    构建命令:

      

    g ++ -m64 CTest.cpp -I / import / bitbucket / JDK / jdk1.6.0_26 / include -I / import / bitbucket / JDK / jdk1.6.0_26 / include / linux -L / import / bitbucket / JDK / jdk1.6.0_26 / jre / lib / amd64 -L / import / bitbucket / JDK / jdk1.6.0_26 / jre / lib / amd64 / server -ljava -ljvm

2 个答案:

答案 0 :(得分:0)

您的堆栈食物似乎有些错误,但如果使用-O0则不是

此外,sun上的JVM可能会有所不同,或者在solaris上运行时可以使用更少的堆栈空间。

您是如何限制Linux和Solaris上的堆栈大小的?

更新:是的,JVM使用different settings on OS Solaris and OS Linux:

  

-XX:ThreadStackSize = 512线程堆栈大小(以KB为单位)。 (0表示使用默认堆栈大小)[Sparc:512; Solaris x86:320(在5.0及更早版本中为256之前的版本); Sparc 64位:1024; Linux amd64:1024(5.0及更早版本中为0);所有其他人.0。]

我不知道这是关于主线程的设置,但是这表明solaris jvm将使用与linux amd64 jvm不同的内存设置。

=== UPDATE2

JNI_CreateJavaVM中的第一个操作是thread creation,因为JVM本身是高度线程化的:

  result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again);
  if (result == JNI_OK) {
    JavaThread *thread = JavaThread::current();
    /* thread is thread_in_vm here */
    *vm = (JavaVM *)(&main_vm);

因此,线程是在调用CreateJavaVM

时创建的

更改“CompilerThreadStackSize”全局变量,因为(!!!!!!!!! AAA我丢失了所有来源我添加回答!!!为什么编辑时没有草稿自动保存?)

默认情况下,AMD64 Linux, JVM has 4M编译器线程堆栈和Solaris SPARC64's has 2M编译器线程堆栈默认情况下。通常的线程在Linux上有1M堆栈,在Solaris上有2M堆栈。

使用1限制linux上的编译器堆栈大小

  

-XX:CompilerThreadStackSize调整堆栈大小

该值以kb为单位。尝试在两个操作系统上将其设置为2048。

答案 1 :(得分:0)

确定。现在我可以在f()中重现一个SIGSEGV;我用的是i386 jvm,有点老了。我们调试内存分配。

$ cat gdb.how
b main
r
b mmap
commands
x/x $sp+4
x/x $sp+8
bt
c
end
c

您可以将$sp+4$sp+8更改为+8和+16或类似。 gdb的第一个输出应该看起来像“00000000,00001000”。我建议你为jvm(我这样做)调整符号。

$ gdb  -x gdb.how ./a.out  > gdb.log
quit
y

现在,让我们看一下如何为线程分配内存:

$ grep Breakpoint\ 2, -A4 gdb.log | grep pthread_create -B 2 | grep 0x00 |cut -d : -f 2 |
perl -e '$a=0;while(<>){s/0x0//;$a+=$_;};print "ibase=16\n".uc($a)."\n";'|bc
4616192

它是所有线程堆栈大小的总和。您可以删除此命令的某些部分以查看实际分配,我有7个使用Sun JVM创建的线程。

现在您可以尝试更改一些选项并检查为线程堆栈分配了多少内存。

我得到的......这很有趣。我有ulimit -s为8192。 如果我使用./a.out开始./a.out,我会得到一个SEGV

$ ./a.out
Segmentation fault

但是如果我以(./a.out )开头(从bash-subshel​​l开始);没有分段错误。