Подтвердить что ты не робот

Мониторинг использования памяти без кучи JVM

Обычно мы сталкиваемся с проблемами OutOfMemoryError из-за проблемы с конфигурацией размера кучи или констанг.

Но все JVM-память не является перменом или кучей. Насколько я понимаю, он также может быть связан с Threads/Stacks, собственным кодом JVM...

Но используя pmap, я вижу, что процесс распределяется с помощью 9.3G, что составляет 3,3 Гбайт памяти памяти.

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

Я не использую прямой доступ к памяти без кучи (MaxDirectMemorySize имеет значение по умолчанию 64 м)

Context: Load testing
Application: Solr/Lucene server
OS: Ubuntu
Thread count: 700
Virtualization: vSphere (run by us, no external hosting)

JVM

java version "1.7.0_09"
Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode)

Tunning

-Xms=6g
-Xms=6g
-XX:MaxPermSize=128m

-XX:-UseGCOverheadLimit
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSClassUnloadingEnabled

-XX:+OptimizeStringConcat
-XX:+UseCompressedStrings 
-XX:+UseStringCache 

Карты памяти:

https://gist.github.com/slorber/5629214

vmstat

procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 1  0   1743    381      4   1150    1    1    60    92    2    0  1  0 99  0

свободный

             total       used       free     shared    buffers     cached
Mem:          7986       7605        381          0          4       1150
-/+ buffers/cache:       6449       1536
Swap:         4091       1743       2348

Top

top - 11:15:49 up 42 days,  1:34,  2 users,  load average: 1.44, 2.11, 2.46
Tasks: 104 total,   1 running, 103 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.5%us,  0.2%sy,  0.0%ni, 98.9%id,  0.4%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   8178412k total,  7773356k used,   405056k free,     4200k buffers
Swap:  4190204k total,  1796368k used,  2393836k free,  1179380k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                 
17833 jmxtrans  20   0 2458m 145m 2488 S    1  1.8 206:56.06 java                                                                                                                                    
 1237 logstash  20   0 2503m 142m 2468 S    1  1.8 354:23.19 java                                                                                                                                    
11348 tomcat    20   0 9184m 5.6g 2808 S    1 71.3 642:25.41 java                                                                                                                                    
    1 root      20   0 24324 1188  656 S    0  0.0   0:01.52 init                                                                                                                                    
    2 root      20   0     0    0    0 S    0  0.0   0:00.26 kthreadd             
...

df → tmpfs

Filesystem                1K-blocks     Used Available Use% Mounted on
tmpfs                       1635684      272   1635412   1% /run

Основная проблема:

  • На сервере имеется 8 ГБ физической памяти
  • Куча Solr принимает только 6G
  • Существует 1,5 ГБ свопа.
  • Swappiness = 0
  • Потребление кучи кажется соответствующим образом настроенным.
  • Работа на сервере: только Solr и некоторые материалы мониторинга
  • У нас есть правильное среднее время отклика
  • Мы иногда имеем аномальные длинные паузы, до 20 секунд.

Я предполагаю, что паузы могут быть полным GC на сменной куче?

Почему так много свопов?

Я даже не знаю, является ли это JVM, что делает обмен сервером, или если это что-то скрытое, которое я не вижу. Возможно, кеш страниц ОС? Но не уверен, почему ОС создаст записи кэша страницы, если это создает обмен.

Я рассматриваю возможность тестирования трюка mlockall, используемого в некоторых популярных хранилищах на базе Java/NoSQL, таких как ElasticSearch, Voldemort или Cassandra: check Сделать JVM/Solr не swap, используя mlockall


Edit:

Здесь вы можете увидеть максимальную кучу, используемую кучу (синий), используемый swap (красный). Кажется, что это связано.

Swap and Heap

Я вижу с Graphite, что существует много ParNew GC, происходящих регулярно. И есть несколько CMS GC, которые соответствуют негативному уменьшению изображения кучи.

Паузы, похоже, не коррелируют с уменьшением кучи, но регулярно распределяются между 10:00 и 11:30, так что это может быть связано с ParNew GC, я думаю.

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

4b9b3361

Ответ 1

Ваша куча фактически использует 6.5 ГБ виртуальной памяти (это может включать в себя perm gen)

У вас есть куча потоков с использованием стеков 64 МБ. Непонятно, почему некоторые из них и другие используют по умолчанию 1 МБ.

Общее количество виртуальной памяти составляет 9,3 млн. КБ. Я бы только беспокоился о размере резидента.

Попробуйте использовать top, чтобы найти резидентный размер процесса.

Вы можете найти эту программу полезной

    BufferedReader br = new BufferedReader(new FileReader("C:/dev/gistfile1.txt"));
    long total = 0;
    for(String line; (line = br.readLine())!= null;) {
        String[] parts = line.split("[- ]");
        long start = new BigInteger(parts[0], 16).longValue();
        long end = new BigInteger(parts[1], 16).longValue();
        long size = end - start + 1;
        if (size > 1000000)
            System.out.printf("%,d : %s%n", size, line);
        total += size;
    }
    System.out.println("total: " + total/1024);

Если у вас нет библиотеки JNI, использующей память, я предполагаю, что у вас много потоков, каждая из которых имеет собственное пространство стека. Я бы проверил количество потоков, которые у вас есть. Вы можете уменьшить максимальное количество стека на поток, но лучшим вариантом может быть сокращение количества потоков, которые у вас есть.

Память выключенной памяти по определению неуправляема, поэтому ее нелегко "настроить" как таковую. Даже настройка кучи не простая.

Размер стека по умолчанию для 64-битных JVM составляет 1024 КБ, поэтому 700 потоков будут использовать 700 МБ виртуальной памяти.

Не следует путать размеры виртуальной памяти для размеров резидентной памяти. Виртуальная память в 64-битном приложении почти бесплатна, и вам нужен только резидентный размер.

Как я вижу, у вас всего 9,3 ГБ.

  • Куча 6.0 ГБ.
  • 128 MB perm gen
  • 700 МБ стеков.
  • < 250 разделяемых библиотек
  • 2.2 ГБ неизвестной (я подозреваю, что виртуальная память не является резидентной памятью)

В последний раз, когда у кого-то была эта проблема, у них было намного больше потоков, чем они, хотя и должны. Я бы проверял максимальное количество потоков, которые у вас были, поскольку это пик, который определяет виртуальный размер. например было ли это ближе к 3000?


Хммм каждая из этих пар является потоком.

7f0cffddf000-7f0cffedd000 rw-p 00000000 00:00 0 
7f0cffedd000-7f0cffee0000 ---p 00000000 00:00 0

и они предполагают, что теперь у вас чуть меньше 700 потоков.

Ответ 2

Достаточно удобный способ контроля (и частичного изменения) параметров среды выполнения экземпляра JVM - это VisualVM:

PS
(Удалена)

ПФС Я вспомнил другой инструмент, который я использовал некоторое время назад: Visual GC. Он показывает вам визуально подробно, что происходит внутри управления памятью JVM, здесь некоторые скриншоты. Очень мощный, и его можно даже интегрировать с плагином в VisualVM (см. Раздел плагинов на главной странице VisualVM).

PPPS
We sometimes have anormaly long pauses, up to 20 seconds. [...] I guess the pauses could be a full GC on a swapped heap right?
Да, это возможно. Эти длительные паузы могут быть вызваны полным GC даже на необработанных кучах. С VisualVM вы можете отслеживать, будет ли полный GC в момент паузы ~ 20 секунд. Я предлагаю запустить VisualVM на другом хосте и подключить его к процессу JVM на вашем виртуальном сервере через явный JMX, чтобы не фальсифицировать измерения с помощью дополнительная нагрузка. Вы можете оставить эту установку за несколько дней/недель и, следовательно, собрать окончательную информацию об этом явлении.

Afaics с текущей информацией, на данный момент есть только следующие возможности:

  • наблюдаемые паузы происходят одновременно с полным GC: JVM настроен неправильно. Вы можете облегчить это с помощью параметров JVM и, возможно, выбрать другой алгоритм/движок GC (вы пробовали CMS и G1 GC? Подробнее о том, как это происходит, например, здесь)
  • наблюдаемые паузы не совпадают с полным GC в JVM: причиной может быть физический виртуальный хост. Проверьте свои SLA (сколько виртуальной оперативной памяти гарантировано находится в физической памяти) и обратитесь к поставщику услуг, запрашивающему мониторинг виртуального сервера.

Я должен был упомянуть, что VisualVM поставляется с Java. И JConsole, также поставляемый с Java, который легче и компактнее VisualVM (но не имеет плагинов, без профилирования и т.д.), Но дает аналогичный обзор.

Если настройка JMX-соединения для VisualVM/JConsole/VisualGC слишком сложна на данный момент, вы можете прибегнуть к параметрам java файла: -XX:+PrintGC -XX:+PrintGCTimeStamps -Xloggc:/my/log/path/gclogfile.log. Эти параметры заставят JVM записывать в указанный файл журнала запись для каждого запуска GC. Этот вариант также хорошо подходит для долгосрочного анализа и, вероятно, является одним из наименьших издержек на вашем JVM.

Снова подумав (и снова) о вашем вопросе: если вы задаетесь вопросом, откуда возникают дополнительные 3+ GB, вот вопрос . Я лично использую коэффициент x1.5 как правило большого пальца.