2013-05-04 10 views
1

У меня есть приложение Java, которое использует собственную библиотеку для некоторых своих функций. Он использует JNI для управления собственной библиотекой, а также получает асинхронный обратный вызов из библиотеки. Вы можете думать об этом как о интерфейсе Java и о родном бэкэнде, которые общаются друг с другом.Отладка утечки памяти JVM

Я столкнулся с утечкой памяти. Вскоре после запуска приложения память медленно, но неуклонно увеличивается. Поэтому я попытался посмотреть, что может вызвать утечку.

Во-первых, я попытался заменить внешний интерфейс Java простым текстовым интерфейсом на C++. Таким образом, приложение не использует Java никоим образом - и утечки прекратились. Поэтому проблема должна быть в интерфейсе Java.

Итак, я выстрелил в jvisualVM, чтобы увидеть, увеличивается ли куча - и оказалось, что нет. Размер кучи Java был довольно постоянным. Я даже запустил программу с xmx32m, но память постоянно увеличивалась за 100 метров без каких-либо OutOfMemoryError. Фактически, jvisualVM продемонстрировал кучу Java около 7 м.

Итак, я углубился в программу с помощью WinDbg. Я проанализировал образцы кучи с !heap -s командой, и я получил это:

куч на свеже запуска программы:

0:059> !heap -s 
LFH Key     : 0x382288b9 
Termination on corruption : ENABLED 
    Heap  Flags Reserv Commit Virt Free List UCR Virt Lock Fast 
        (k)  (k) (k)  (k) length  blocks cont. heap 
----------------------------------------------------------------------------- 
00330000 00000002 2048 1704 2048  22 71  2 0  0 LFH 
005b0000 00001002 1088 212 1088  68  3  2 0  0 LFH 
00aa0000 00001002 1088 108 1088  15  7  2 0  0 LFH 
004f0000 00001002 15424 12876 15424 1372 89  9 0  1 LFH 
... 

0:059> !heap -stat -h 004f0000 
heap @ 004f0000 
group-by: TOTSIZE max-display: 20 
    size  #blocks  total  (%) (percent of total busy bytes) 
    2b110 20 - 562200 (60.36) 
    98 166e - d5150 (9.33) 
    6cd20 1 - 6cd20 (4.77) 
    ... 

куч на программу, которая работает уже в течение около получаса:

0:046> !heap -s 
LFH Key     : 0x5e47ba72 
Termination on corruption : ENABLED 
    Heap  Flags Reserv Commit Virt Free List UCR Virt Lock Fast 
        (k)  (k) (k)  (k) length  blocks cont. heap 
----------------------------------------------------------------------------- 
006b0000 00000002 2048 1744 2048  46 92  2 0  0 LFH 
00200000 00001002 1088 220 1088  68  3  2 0  0 LFH 
00950000 00001002 1088 108 1088  15  7  2 0  0 LFH 
001b0000 00001002 47808 31936 47808 1855 102 12 0  0 LFH 
... 

0:046> !heap -stat -h 001b0000 
heap @ 001b0000 
group-by: TOTSIZE max-display: 20 
    size  #blocks  total  (%) (percent of total busy bytes) 
    98 59d1 - 355418 (36.67) 
    2b110 10 - 2b1100 (29.61) 
    6cd20 1 - 6cd20 (4.68) 
    ... 

Теперь ясно видно, что утечки вызваны растущим числом блоков с размером 98. Но когда я пытаюсь проанализировать один из блоков с помощью !heap -p -a, я получаю:

*** ERROR: Symbol file could not be found. Defaulted to export symbols for jvm.dll

без следов стека. Таким образом, блоки выделяются где-то внутри jvm.dll, и поскольку для JVM нет pdbs, я не могу отлаживать утечку дальше.

Мне удалось определить, где происходит утечка в моем коде. Все callbacs в интерфейсе Java проходят через одну функцию:

void callback(JNIEnv *env, int stream, double value, char *callbackName){ 
    jclass jni = env->FindClass("nativ/Callbacks"); 
    jmethodID callbackMethodID = env->GetStaticMethodID(jni, callbackName, "(ID)V"); 
    jvalue params[2]; 
    params[0].i = (long)(stream); 
    params[1].d = value; 
    env->CallStaticVoidMethodA(jni, callbackMethodID, params); //commenting this out stops the leaks 
} 

Когда я закомментируйте последнюю команду, утечки остановить, но я не получаю никакой обратной обратно в веб-интерфейсе.

Это может быть ошибка JVM? Как узнать?

+0

Windows heaps - это старый API. Большинство реализаций malloc() не используют их. –

+0

@brian Не могли бы вы рассказать об этом? Какие другие API-интерфейсы используются? И как это объясняет увеличение, которое я вижу на выходе Windbg? –

+1

Все malloc() Я посмотрел на использование VirtualAlloc(). Если рост кучи соответствует росту размера процесса, то это некоторый API, использующий кучи окон. –

ответ

0

malloc() внутренне вызывает HeapAlloc(). Я думаю, вам нужен метод «Release», чтобы освободить память, выделенную JVM, если ваша библиотека содержит ссылку на внутреннее состояние JVM.

Смежные вопросы