JNI_CreateJavaVM в Linux разрушает стек? - PullRequest
4 голосов
/ 23 августа 2011

Это происходит в Linux 2.6.18-238.5.1.el5 с 64-битным приложением.Мой размер стека процессов составляет 10 МБ.Однако после (успешного) вызова JNI_CreateJavaVM у меня остается только 1-2 МБ в стеке.Если я прошёл мимо этого - у меня ошибка памяти, как будто я переполняю стек.

Несколько замечаний:

  1. Если я не создаю JVM, то получаюдоступ ко всему моему стеку размером 10 МБ.
  2. Та же самая программа тестирования с тем же make-файлом прекрасно работает на Solaris даже при вызове JVM

Источник теста:

#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 / сервер -ljava -ljvm

Ответы [ 2 ]

0 голосов
/ 25 августа 2011

Хорошо.Теперь я могу воспроизвести SIGSEGV в f();Я использую 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);нет ошибки сегментации.

0 голосов
/ 23 августа 2011

Ваш стек-пожиратель кажется глючным, но это не так, если используется -O0

Кроме того, JVM на солнце может варьироваться или использовать меньше места в стеке при работе на Solaris.

Как вы ограничивали размер стека в Linux и Solaris?

Обновление: да, JVM использует различные настройки в ОС Solaris и ОС Linux:

-XX: ThreadStackSize = 512 Размер стека потока (в килобайтах). (0 означает использовать размер стека по умолчанию) [Sparc: 512; Solaris x86: 320 (ранее было 256 в 5.0 и более ранних версиях); Sparc 64 бит: 1024; Linux amd64: 1024 (было 0 в 5.0 и ранее); все остальные 0.]

Я не знаю, является ли этот параметр основным потоком, но это указывает на то, что солярис jvm будет использовать другие параметры памяти, чем linux amd64 jvm.

=== ОБНОВЛЕНИЕ2

самыми первыми операциями в JNI_CreateJavaVM являются создание потока , поскольку сама 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 по умолчанию имеет стек потоков компилятора 4M , а Solaris SPARC64 имеет стек потоков компиляции 2M по умолчанию. Обычные потоки получают 1M стека на Linux и 2M стека на Solaris.

Используйте 1 для ограничения размера стека компилятора в linux

-XX: CompilerThreadStackSize для настройки размера стека

значение в кб. Попробуйте установить его на 2048 в обеих ОС.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...