Почему нативная библиотека использует в 1,5 раза больше памяти при использовании Java, чем при использовании C-Programm в Linux? - PullRequest
7 голосов
/ 20 января 2010

Я написал библиотеку на C, которая потребляет много памяти (миллионы маленьких блоков). Я написал программу c, которая использует эту библиотеку. И я написал Java-программу, которая использует ту же библиотеку. Программа на Java представляет собой очень тонкий слой вокруг библиотеки. По сути, есть только один собственный метод, который вызывается, выполняет всю работу и возвращает часы спустя. Дальнейшая связь между Java и нативной библиотекой с использованием интерфейса вызова Java отсутствует. Также нет объектов Java, которые занимают значительное количество памяти.

Таким образом, c-программа и Java-программа очень похожи. Все вычисления / распределение памяти происходит внутри собственной библиотеки. Еще. При выполнении программа c потребляет 3 ГБ памяти. Но программа Java потребляет 4,3 ГБ! (Сумма VIRT указана сверху)

Я проверил карту памяти процесса Java (используя pmap). Только 40 МБ используются библиотеками. Поэтому дополнительные библиотеки, загружаемые Java, не являются причиной.

У кого-нибудь есть объяснение этому поведению?

РЕДАКТИРОВАТЬ : Спасибо за ответы до сих пор. Чтобы сделать его немного более понятным: код Java ничего не делает, кроме как вызывает собственную библиотеку ONCE ! Куча Java имеет стандартный размер (возможно, 60 МБ) и не используется (за исключением одного класса, содержащего метод main, а другого класса, вызывающего собственную библиотеку).

Метод нативной библиотеки является долгосрочным и выполняет много malloc и освобождает. Фрагментация - это одно из объяснений, о которых я тоже думал. Но поскольку Java-код не активен, поведение фрагментации должно быть одинаковым для Java-программы и c-программы. Поскольку он отличается, я также предполагаю, что используемые реализации malloc отличаются при запуске в программе на языке c или в программе на Java.

Ответы [ 6 ]

3 голосов
/ 20 января 2010

Просто догадываюсь: вы можете использовать реализацию не по умолчанию malloc при работе внутри JVM, которая настроена на конкретные потребности JVM и создает больше издержек, чем malloc общего назначения в вашей обычной реализации libc.

2 голосов
/ 28 января 2010

Простите, ребята. Неправильные предположения.

Я привык к 64 МБ реализациям Sun Java, которые использовались для максимального размера кучи по умолчанию. Но я использовал openjdk 1.6 для тестирования. Openjdk использует часть физической памяти, если не был явно указан максимальный размер кучи. В моем случае четверть. Я использовал машину на 4 ГБ. Таким образом, четверть составляет 1 ГБ. В этом разница между C и Java.

К сожалению, это поведение нигде не задокументировано. Я нашел это, глядя на исходный код openjdk (arguments.cpp):

// If the maximum heap size has not been set with -Xmx,
// then set it as fraction of the size of physical memory,
// respecting the maximum and minimum sizes of the heap.
1 голос
/ 20 января 2010

Java должна иметь непрерывную память для своей кучи, чтобы она могла выделять максимальный размер памяти в качестве виртуальной памяти. Однако это не потребляет физической памяти и может даже не потреблять подкачки. Я бы проверил, насколько увеличивается твоя резидентная память.

0 голосов
/ 20 января 2010

Вот предложение по борьбе с ним.

Завершите работу кода C с помощью стандартного вызова malloc и используйте альтернативную версию malloc, которая захватывает память с помощью mmap ing /dev/zero. Вы можете либо изменить реализацию malloc из библиотеки, либо свернуть свою собственную, если чувствуете себя достаточно компетентным для этого.

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

0 голосов
/ 20 января 2010

Трудно сказать, но я думаю, что суть проблемы в том, что в вашем приложении есть две кучи, которые необходимо поддерживать - стандартная куча Java для размещения объектов Java (поддерживаемая JVM), и куча C, которая поддерживается при вызовах malloc / free. Трудно точно сказать, что происходит, не видя некоторого кода.

0 голосов
/ 20 января 2010

Существуют различные факторы, которые необходимо учитывать, особенно в таких языках, как Java, Java запускается на виртуальной машине, а сборка мусора обрабатывается средой выполнения Java, так как при использовании Java Invocation Interface для переключения или выполнения нативного метода в нативной библиотеке, поскольку должны быть средства для выделения места в стеке, переключения на нативный код, выполнения нативного метода, переключения обратно на виртуальную машину Java и, возможно, каким-то образом, пространство в стеке не было освобождено - это то, что я склонен думать.

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

...