这发生在带有64位应用程序的linux 2.6.18-238.5.1.el5上。我的进程堆栈大小是10MB。但是,在(成功)调用JNI_CreateJavaVM后,我似乎只剩下1-2 MB的堆栈。如果我越过它 - 我得到了内存故障,好像我在堆栈中溢出。
一些注意事项:
测试来源:
#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
答案 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-subshell开始);没有分段错误。