вторник, 12 декабря 2017 г.

JAVA memory usage. Часть 3


При использовании java-приложений в контейнерах, которым необходимо ограничивать ресурсы, возникает необходимость в точном определении количества используемой памяти  Java-машиной
В первых двух частях (Часть 2 Часть 1) разбирались принципы выделения памяти. В третьей, закючительной, будут рассмотрены способы получения размеров отдельных областей памяти с помощью mbean и NMT

Подготовительные работы

  1. Включаем NativeMemoryTracking, добавляя соответствующие ключи
    https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html
    -XX:NativeMemoryTracking=summary
    или
    -XX:NativeMemoryTracking=detail
  2. Снимаем статстику
    /opt/oracle/java/latest/bin/jcmd 29 VM.native_memory summary
    примерный вывод.
    Total: reserved=20272361KB, committed=19037005KB
    -                 Java Heap (reserved=17825792KB, committed=17825792KB)
                                (mmap: reserved=17825792KB, committed=17825792KB)
    -                     Class (reserved=1097201KB, committed=54769KB)
                                (classes #9178)
                                (malloc=1521KB #19960)
                                (mmap: reserved=1095680KB, committed=53248KB)
    -                    Thread (reserved=129906KB, committed=129906KB)
                                (thread #359)
                                (stack: reserved=127640KB, committed=127640KB)
                                (malloc=1175KB #1820)
                                (arena=1091KB #716)
    -                      Code (reserved=261351KB, committed=68431KB)
                                (malloc=11751KB #12492)
                                (mmap: reserved=249600KB, committed=56680KB)
    -                        GC (reserved=134795KB, committed=134795KB)
                                (malloc=68983KB #503)
                                (mmap: reserved=65812KB, committed=65812KB)
    -                  Compiler (reserved=804KB, committed=804KB)
                                (malloc=673KB #1296)
                                (arena=131KB #3)
    -                  Internal (reserved=522778KB, committed=522774KB)
                                (malloc=522742KB #41658)
                                (mmap: reserved=36KB, committed=32KB)
    -                    Symbol (reserved=11660KB, committed=11660KB)
                                (malloc=10182KB #92944)
                                (arena=1479KB #1)
    -    Native Memory Tracking (reserved=2973KB, committed=2973KB)
                                (malloc=237KB #3598)
                                (tracking overhead=2736KB)
    -               Arena Chunk (reserved=546KB, committed=546KB)
                                (malloc=546KB)
    -                   Unknown (reserved=284556KB, committed=284556KB)
                                (mmap: reserved=284556KB, committed=284556KB)
    Что означают эти области памяти можно почитать в предыдущих частях.

Получение результатов.

В таблице перечислены основные потребители памяти. Для большинства из них существуют MBean, с помошью которых можно получить искомое значение и включать NMT не бязательно.




область памятиMBean



Java Heap
java.lang Memory HeapMemoryUsage.max


Thread
java.lang Threading PeakThreadCount



Code

java.lang MemoryPool Code Cache Usage.max (reserved)
java.lang MemoryPool Code Cache Usage.commited (commited)





java.lang Memory NonHeapMemory Usage.committed (committed)



Class
java.lang MemoryPool Metaspace Usage.max (reserved)
java.lang MemoryPool Metaspace Usage.commited (commited)





CompressedClassSpace
java.lang MemoryPool Compressed Class Space Usage.max (reserved)
java.lang MemoryPool Compressed Class Space Usage.committed (commited)


Symbol 




BufferPool
jmx["java.nio:type=BufferPool,name=direct",MemoryUsed]


GC



Unknown







Java Heap

Размер Haep должен быть ограничен ключом -Xmx.
Для оценки верхней границы области памяти heap берётся значение этого этого ключа или соответствующего mbean.

Class

Метаинформация классов и, если HEAP меньше 32Гб, область для хранения соответствия сжатых указателей. Для ограничения занимаемого этой областью памяти размера необходимо:
задать -XX:CompressedClassSpaceSize
задать -XX:MaxMetaspaceSize
-                     Class (reserved=1146767KB, committed=110607KB)
                            (classes #19918)
                            (malloc=1935KB #27656)
                            (mmap: reserved=1144832KB, committed=108672KB)

Для оценки верхней границы области памяти используется максимальное значение за продолжительное время работы JVM, снятое под характерной нагрузкой (committed)

Thread

Размер занимаемой памяти стэками потоков. Размер стэка для потока задаётся ключом -Xss
Текущее значение можно посмотреть в ps -ef | grep Xss --color

Если не задано, default-значение можно посмотреть так:
/opt/oracle/java/latest/bin/java -XX:+PrintFlagsFinal -version | grep ThreadStackSize 
      intx VMThreadStackSize   = 1024       {pd product}

Память под стэки трэдов (Mb) = VMThreadStackSize*Number Of Threads/1024

Для оценки верхней границы потребления памяти необходимо брать значение максимального кол-во трэдов за период работы.

BufferPool

Область памяти, использующаяся JVM при работе c "native IO" (сокеты, файлы и т.д.) Необходимо выбирать на основе значения соответствующего mbean-а java.nio:type=BufferPool,name=direct",MemoryUsed под нагрузкой за продолжительный период времени.

GC, Uncnown

Область памяти, используемая сборщиком мусора. Для получения количества памяти, занимаемой сборщиком мусора необходимо включать NMT или пользоваться приблизительными значениями. Как показано во второй части, область сборщика мусора пропорциональна размеру heap.

вторник, 27 июня 2017 г.

Leaking memory для JDK 8

А релизе 8u131 решена проблем с текущей памятью JVM.
Проблема наблюдается в релизах младше 131

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8164293

среда, 21 июня 2017 г.

JAVA memory usage. Часть 2.

Native Memory Tracking.

С версии 1.8u40 в Oracle JDK включена возможность получать информацию о текущем использовании NativeMemory - Native Memory Tracking.


Для включения NMT необходимо добавить ключ  -XX:NativeMemoryTracking=detail
java -Xms450m -Xmx512m -XX:NativeMemoryTracking=detail -jar /opt/gcviewer/gcviewer-1.35-SNAPSHOT.jar
Для просмотра общей ниформации используется утилита  jcmd с ключём summary
/opt/oracle/java/latest/bin/jcmd <pid> VM.native_memory summary
Native Memory Tracking:


-                 Java Heap (reserved=524288KB, committed=460800KB)
                            (mmap: reserved=524288KB, committed=460800KB)

-                     Class (reserved=1072564KB, committed=26548KB)
                            (classes #3395)
                            (malloc=5556KB #2675)
                            (mmap: reserved=1067008KB, committed=20992KB)

-                    Thread (reserved=20648KB, committed=20648KB)
                            (thread #21)
                            (stack: reserved=20560KB, committed=20560KB)
                            (malloc=64KB #106)
                            (arena=23KB #40)

-                      Code (reserved=250784KB, committed=8012KB)
                            (malloc=1184KB #2669)
                            (mmap: reserved=249600KB, committed=6828KB)

-                        GC (reserved=24933KB, committed=24729KB)
                            (malloc=5773KB #176)
                            (mmap: reserved=19160KB, committed=18956KB)

-                  Compiler (reserved=150KB, committed=150KB)
                            (malloc=20KB #110)
                            (arena=131KB #3)

-                  Internal (reserved=5853KB, committed=5853KB)
                            (malloc=5821KB #4999)
                            (mmap: reserved=32KB, committed=32KB)

-                    Symbol (reserved=4901KB, committed=4901KB)
                            (malloc=2432KB #2557)
                            (arena=2469KB #1)

-    Native Memory Tracking (reserved=362KB, committed=362KB)
                            (malloc=121KB #1921)
                            (tracking overhead=240KB)

-               Arena Chunk (reserved=187KB, committed=187KB)
                            (malloc=187KB)

Полный список "NMT Memory Categories" с их описанием можно посмотреть тут.

1. Java Heap

Область памяти в которой создаются объекты приложения.
-                 Java Heap (reserved=524288KB, committed=460800KB)
                            (mmap: reserved=524288KB, committed=460800KB)

На примере, рассмотренном в предыдущем посте, описано, что ключ Xmx указывает количество памяти, выделяемое в виртуальном адресном пространстве процесса. Эта память никак не мапится на физическую память сервера.
-Xmx512m - reserved memory  (reserved=524288KB)
ключ Xms указывает, какое количество памяти должно быть выделено (mmaped), но не обязательно использовано для heap-области процесса JVM на момент его старта. Эта память отображаться как Commited Memory. Если Xms меньше Xmx, то количество commited memory может увеличиваться по мере необходимости до порога, заданного значением reserved memory.
В примере -Xms450m - commited memory (committed=460800KB).

более подробную статистику по процессу можно посмотреть с помощью
/opt/oracle/java/latest/bin/jcmd <pid> VM.native_memory detail
Статитстика, относящая к Heap представлена сразу после суммарной статистики
Virtual memory map:
[0x00000000e0000000 - 0x0000000100000000] reserved 524288KB for Java Heap from
    [0x00007f9986b73552] ReservedSpace::initialize(unsigned long, unsigned long, bool, char*, unsigned long, bool)+0xc2
    [0x00007f9986b73f2e] ReservedHeapSpace::ReservedHeapSpace(unsigned long, unsigned long, bool, char*)+0x6e
    [0x00007f9986b40f2b] Universe::reserve_heap(unsigned long, unsigned long)+0x8b
    [0x00007f99869f7474] ParallelScavengeHeap::initialize()+0x84
        [0x00000000e0000000 - 0x00000000f2c00000] committed 307200KB from
            [0x00007f9986a431e3] PSVirtualSpace::expand_by(unsigned long)+0x53
            [0x00007f9986a332f7] PSOldGen::initialize(ReservedSpace, unsigned long, char const*, int)+0xb7
            [0x00007f9986387cea] AdjoiningGenerations::AdjoiningGenerations(ReservedSpace, GenerationSizer*, unsigned long)+0x39a
            [0x00007f99869f75c6] ParallelScavengeHeap::initialize()+0x1d6
        [0x00000000f5580000 - 0x00000000feb80000] committed 153600KB from
            [0x00007f9986a431e3] PSVirtualSpace::expand_by(unsigned long)+0x53
            [0x00007f9986a441a5] PSYoungGen::initialize_virtual_space(ReservedSpace, unsigned long)+0x75
            [0x00007f9986a44b0e] PSYoungGen::initialize(ReservedSpace, unsigned long)+0x3e
            [0x00007f9986387c95] AdjoiningGenerations::AdjoiningGenerations(ReservedSpace, GenerationSizer*, unsigned long)+0x345
Под heap было выделено пространство  [0x00000000e0000000 - 0x0000000100000000] reserved 524288KB
В него включено
[0x00000000e0000000 - 0x00000000f2c00000] committed 307200KB - под Old Gen
[0x00000000f5580000 - 0x00000000feb80000] committed 153600KB - под  Young Gen

С помощью команды
pmap -X <pid>
пожно получить аналогичные данные

java -Xms450m -Xmx512m -XX:NativeMemoryTracking=detail -jar /opt/gcviewer/gcviewer-1.35-SNAPSHOT.jar
         Address Perm   Offset Device    Inode    Size    Rss    Pss Referenced Anonymous ShmemPmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked Mapping
        00400000 r-xp 00000000  00:26   315842       4      4      2          4         0              0              0               0    0       0      0 java
        00600000 rw-p 00000000  00:26   315842       4      4      4          4         4              0              0               0    0       0      0 java
        021eb000 rw-p 00000000  00:00        0     132     20     20         20        20              0              0               0    0       0      0 [heap]
        e0000000 rw-p 00000000  00:00        0  307200     12     12         12        12              0              0               0    0       0      0
        f2c00000 ---p 00000000  00:00        0   42496      0      0          0         0              0              0               0    0       0      0
        f5580000 rw-p 00000000  00:00        0  153600 113832 113832     113832    113832              0              0               0    0       0      0
        feb80000 ---p 00000000  00:00        0   20992      0      0          0         0              0              0               0    0       0      0
       100000000 rw-p 00000000  00:00        0    2816   2768   2768       2768      2768              0              0               0    0       0      0
Диапазон адресов, отданных под heap выделен красным.
Текущие области памяти New и Old выделены синим. Атрибуты rw-p в столбце Per:
rw - возможна запись и чтение памяти (PROT_READ | PROT_WRITE аргументы были заданы при выделении этой области памяти)
p - память выделена как private
сочетание разрешение ---p означает, что память пока только заразервирована.

JVM non Heap (Native) memory.


Все остальные области памяти процесса JVM относятся к так называемой non-Heap memory. Эти области памяти выделяются в Native memory ОС. Максимальное количество Native памяти, которую может использовать JVM процесс не ограничено по умолчанию.

2. Class

Эта область памяти используется для хранения метаданных классов. Данная область памяти использует Native память ОС. Верхняя граница количества памяти, использующейся под class metadata задаётся ключём -XX:MaxMetaspaceSize.

-                     Class (reserved=1072564KB, committed=26548KB)
                            (classes #3395)
                            (malloc=5556KB #2675)
                            (mmap: reserved=1067008KB, committed=20992KB)

Вывод утилиты показывает, что Reserved память составляет 1 Gb, но она практически не используется. Такой объём reserved memory объясняется nем, что для JVM с размером Heap меньше 32 Гб используется дефолтное значение ключа -XX:+UseCompressedOops. В свою очередь, при использовании этого ключа дефолтное значение ключа -XX:CompressedClassSpaceSize=1G.

1072564KB только резервируется процессом и не обязательно будет использоваться. В выводе видно, что размер committed memory всего 26548KB
Более подробный вывод:
/opt/oracle/java/latest/bin/jcmd <pid> VM.native_memory detail

[0x0000000100000000 - 0x0000000140000000] reserved 1048576KB for Class from
    [0x00007fed5e22c552] ReservedSpace::initialize(unsigned long, unsigned long, bool, char*, unsigned long, bool)+0xc2
    [0x00007fed5e22c78b] ReservedSpace::ReservedSpace(unsigned long, unsigned long, bool, char*, unsigned long)+0x1b
    [0x00007fed5e00d080] Metaspace::allocate_metaspace_compressed_klass_ptrs(char*, unsigned char*)+0x40
    [0x00007fed5e00f55f] Metaspace::global_initialize()+0x4cf
        [0x0000000100000000 - 0x00000001002c0000] committed 2816KB from
            [0x00007fed5e22bfc9] VirtualSpace::expand_by(unsigned long, bool)+0x199
            [0x00007fed5e00b4e6] VirtualSpaceList::expand_node_by(VirtualSpaceNode*, unsigned long, unsigned long)+0x76
            [0x00007fed5e00e300] VirtualSpaceList::expand_by(unsigned long, unsigned long)+0xf0
            [0x00007fed5e00e493] VirtualSpaceList::get_new_chunk(unsigned long, unsigned long, unsigned long)+0xb3

Помимо размера выделенной commited и reserved memory можно обнаружить вызов выделения области сжатых указателей  Metaspace::allocate_metaspace_compressed_klass_ptrs, который резервирует в область размером в гигабайт.
В документации такое поведение объясняется необходимостью содержать отдельную структуру в памяти, обеспечивающую хранение смещения 64 битных указателей классов для работы с 32 битными указателями JVM. Наличие этой области актуально только при значениях ключей -XX:+UseCompressedOops и -XX:+UseCompressedClassesPointers использующихся по умолчанию для Heap меньше 32Gb.
Размер области сжатых указателей звдаётся ключём -XX:CompressedClassSpaceSize
При его чрезмерном уменьшениии возможна ошибка java.lang.OutOfMemoryError: Compressed class space

При отключении использования сжатых указателей (не рекомендуется т.к. даёт большой overhead на использование памяти) ключём -XX:-UseCompressedOops  вывод NMT будет следующим:

java -Xms450m -Xmx512m -XX:-UseCompressedOops -XX:NativeMemoryTracking=detail -jar /opt/gcviewer/gcviewer-1.35-SNAPSHOT.jar

[0x00007fe6f9000000 - 0x00007fe708000000] reserved 245760KB for Code from
    [0x00007fe70f3036e6] ReservedSpace::initialize(unsigned long, unsigned long, bool, char*, unsigned long, bool)+0x256
    [0x00007fe70f303d4c] ReservedCodeSpace::ReservedCodeSpace(unsigned long, unsigned long, bool)+0x2c
    [0x00007fe70ee5ae85] CodeHeap::reserve(unsigned long, unsigned long, unsigned long)+0xa5
    [0x00007fe70ecbfeb0] CodeCache::initialize()+0x80
        [0x00007fe6f9570000 - 0x00007fe6f95a0000] committed 192KB from
            [0x00007fe70f302fc9] VirtualSpace::expand_by(unsigned long, bool)+0x199
            [0x00007fe70ee5ac6c] CodeHeap::expand_by(unsigned long)+0x8c
            [0x00007fe70ecc0200] CodeCache::allocate(int, bool)+0x60
            [0x00007fe70f12c13c] nmethod::new_nmethod(methodHandle, int, int, CodeOffsets*, int, DebugInformationRecorder*, Dependencies*, CodeBuffer*, int, OopMapSet*, 
Ограничить область памяти Calss  можно ключами -XX:MaxMetaspcaseSize и XX:CompressedClassSpaceSize

 3. Thread

Количество памяти, занимаемое стэками потоков. Размер стэка каждого потока задаётся ключём -Xss. Дефолтный размер стэка 1024 байт. Его можно посмотреть так:
/opt/oracle/java/latest/bin/java -XX:+PrintFlagsFinal -version | grep ThreadStackSize

intx VMThreadStackSize = 1024 {pd product}
На каждый поток выделяется стэк размером VMThreadStackSize.
В выводе NMT каждый стэк выглядит так:
[0x00007f7a90f84000 - 0x00007f7a91085000] reserved and committed 1028KB for Thread Stack from
    [0x00007f7adc64f884] JavaThread::run()+0x24
    [0x00007f7adc500568] java_start(Thread*)+0x108
Можно заметить, что размер стэка 1028KB, а не 1024КБ.

вывод pmap -X, соответствующий данному потоку показывает, что под него выделено 2 области памяти 12Кб и 1016 Кб.
Address Perm   Offset Device   Inode    Size    Rss    Pss Referenced Anonymous ShmemPmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked Mapping
    7f7a47be2000 ---p 00000000  00:00       0      12      0      0          0         0              0              0               0    0       0      0
    7f7a47be5000 rw-p 00000000  00:00       0    1016     88     88         88        88              0              0               0    0       0      0

Суммарная статистика показывает, что все стэки занимают 20648KB, что соответствует (20648-64-23)/1028=20 потокам.
-                    Thread (reserved=20648KB, committed=20648KB)
                            (thread #21)
                            (stack: reserved=20560KB, committed=20560KB)
                            (malloc=64KB #106)
                            (arena=23KB #40)

4. Code

В процессе работы процесс JVM выполняет некоторый байт-код. JVM может решить, что какой-то кусок кода выполняется достаточно часто и скомпилировать его в native-код. Native-код выполняется значительно быстрее и требует меньше ресурсов чем byte code. Для хранения скомпилированного кода используется native code cache. Размеры этой области задаются ключами
-XX:ReservedCodeCacheSize - максимальное значение
-XX:InitialCodeCacheSize - размер области, выделяемый при старте.
Подбор ReservedCodeCacheSize значения происходит индивидуально для каждого приложения.

При компиляуии код проходит несколько степеней оптимизации.
level 0 - Интерпретатор JVM.
level 1 - C1 с оптимизацией, без профилирования
level 2 - C1 с учётом счётчиков количества обращений и "backedge"
level 3 - C1 с оптимизацией и профилированием
level 4 - C2
Для отключения компиляции в Native код используется ключ -Xint (не рекомендуется)
Для отключения промежуточных фаз компилирования и хранения только кода С2 можно использвать ключ -XX:-TieredCompilation. При этом критерием компиляции станнет значение CompileThreshold.
java -XX:+PrintFlagsFinal -version | grep CompileThreshold
     intx CompileThreshold                          = 10000                               {pd product}
     intx Tier2CompileThreshold                     = 0                                   {product}
     intx Tier3CompileThreshold                     = 2000                                {product}
     intx Tier4CompileThreshold                     = 15000                               {product}


GC

Последняя относительно крупная область Native памяти JVM - память сборщика мусора. Она пропорциональна размеру Heap.
Если JDK1.8 использует сборщик мусора G1, статистика использования памяти этим сборщиком будет примерно такая:

для Xms = 450M область GC составляет около 24Mb
-                        GC (reserved=24933KB, committed=24729KB)
                            (malloc=5773KB #176)
                            (mmap: reserved=19160KB, committed=18956KB)
для Xms = 2G область GC составляет около 80Mb
-                        GC (reserved=82395KB, committed=82395KB)
                            (malloc=5771KB #121)
                            (mmap: reserved=76624KB, committed=76624KB)
для Xms = 4G область GC составляет около 160Mb

-                        GC (reserved=159015KB, committed=159015KB)
                            (malloc=5771KB #121)
                            (mmap: reserved=153244KB, committed=153244KB)


То есть примерно 40 Mb на гигабайт Heap

Для CMS сборщика следует учитывать не только область GC, но и область Unлnown т.к. Native Memory Tracker не умеет (и, наверное, уже никогда не научится) правильно идентифицировать области памяти, использующиеся этим сборщиком.

java +UseConcMarkSweepGC -XX:NativeMemoryTracking=detail -jar /opt/gcviewer/gcviewer-1.35-SNAPSHOT.jar

для Xms = 2G область GC составляет примерно 16+60 = 76Mb

-                        GC (reserved=16891KB, committed=16891KB)
                            (malloc=9359KB #144)
                            (mmap: reserved=7532KB, committed=7532KB)
-                   Unknown (reserved=60648KB, committed=60648KB)
                           (mmap: reserved=60648KB, committed=60648KB)
для Xms = 4G область GC составляет примерно 25+93 = 120Mb

-                        GC (reserved=25083KB, committed=25083KB)
                            (malloc=9359KB #144)
                            (mmap: reserved=15724KB, committed=15724KB)

-                   Unknown (reserved=93928KB, committed=93928KB)
                            (mmap: reserved=93928KB, committed=93928KB)

Особенности окружения

Для glibc 2.12 и 2.17 существует особенность выделения памяти областями по 64 Mb. Данные версии библиотеки используется в Red Hat Enterprise Linux 6 и Red Hat Enterprise Linux 7.  Я использую Fedora release 25 (Twenty Five) c версией пакета glibc-2.24-6.fc25.x86_64, где подобного поведения не наблюдается. При попытках повторить мои действия на ОС RHEL6/7 результаты теоретически должны сильно отличаться от результатов в Fedora 25. Несколько сократить фрагментацию должны помочь ключи:

-XX:CodeCacheExpansionSize=1M -XX:CodeCacheMinimumFreeSpace=1M
-XX:MinMetaspaceExpansion=1M -XX:MaxMetaspaceExpansion=8M




четверг, 15 июня 2017 г.

JAVA memory usage. Часть 1.

В этом посте будет рассмотриваться процесс JVM и в общих чертах описан механизм использования им памяти.

В ОС Linux процессы не работают с памятью напрямую. Каждому процессу выделяется виртуальное пространство, к которому он обращается при необходимости. В момент непосредственного использования памяти ядро системы ассоциирует адрес в виртуальном адресном пространстве процесса со страницами памяти, которыми располагает система (физически существующей памятью). Процесс обеспечивается механизмом lazy allocation.

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

Из принципа работы этого механизма: процессу/процессам ОС может быть выделено больше "виртуальной" памяти, чем физически располагает система. Подобная ситуация не всегда допустима, поэтому процессу, запрашивающему себе память в своём виртуальном адресном пространстве иногда требуется явно указать, как она будет соотносится с физической памятью системы. В связи с этим для дальнейшего понимания вывода диагностических утилит, необходимо ввести классификацию памяти.

Reserved memory - память, которая может быть будет выделена процессу. У любого процесса Reserved memory может быть больше сумы физического объёма памяти в системе.
Выделяется в виртуальном адресном пространстве без выделения физической памяти. Выделяется методом mmap  с указанием ключа PROT_NONE. Т.к. страницы выделены в витр. адресном пространстве, они резервируют часть адресов этого адресного пространства и другие вызовы mmap не будут пытаться использовать уже занятые адреса, но обращния к этим страницам будет вызывать ошибку с отправкой процессу сигнала SIGSEGV.

Commited memory - память в виртуальном адресном пространстве, выделенная процессу. От reserved отличается тем, что резервируется не с флагом PROT_NONE, а, например, с PROT_READ | PROT_WRITE. Страницы commited memory, в отличие от reserved memory, не только зарезервированы в виртуальном адресном пространстве процесса, но и могут быть замаплены на физическую память системы без получения процессом SIGSEGV. При обращении к таким страницам ядро обрабатывает этот вызов, привязывая страницы памяти виртуального адресного пространства процесса и физически существующей памяти прозрачно для процесса.

Resident memory - память, выделенная процессу, в которую процесс записал что-либо.

Как это соотносится с памятью (heap) процесса JVM

Resident memory

Для примера можно рассмотреть процесс
java -jar /opt/gcviewer/gcviewer-1.35-SNAPSHOT.jar
вывод top по этому процессу
  PID USER      PR  NI    VIRT    RES       SHR S  %CPU %MEM  TIME+ COMMAND                  
 7284 user          20   0  5299360 210658  29432 S      0.3       1.6         0:03.74      java   

Столбец RES означает, сколько памяти в данный момент используется процессом. В моём случае используется 210658 килобат. Это resident memory или по-другому RSS (Resident Set Size).
На графике использования heap из jvisualvm синяя область - это часть resident memory процесса. То есть та память, которая заполнена чем-либо.

Использующаяся часть heap - это, конечно, не вся resident memory рассматриваемого процесса. Вся resident memory процесса будет складываться из занятых  Heap и Native областей.

Commited memory.

На том же графике можно увидеть, что текущий Heap size состовляет около 150 Мб.
Текуций heap size JVM - это commited memory.  
Текущий размер heap  - это не вся commited memory рассматриваемого процесса, а её часть. 
Общий объём commited memory процесса складывается из commited memory heap и native областей памяти процесса.


Reserved memory

Если запустить тот же процесс, задав размеры heap ключами -Xms512m -Xmx100G, что заведомо больше, чем есть на моём сервере,
java -Xms512m -Xmx100G, -jar /opt/gcviewer/gcviewer-1.35-SNAPSHOT.jar
вывод top покажет, что занимаемая процессом Resident memory практически не изменилась и составлет 219560 Кбайт
 Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.7 us,  1.1 sy,  0.0 ni, 94.6 id,  0.9 wa,  0.4 hi,  0.3 si,  0.0 st
KiB Mem :  8075464 total,  1616492 free,  3249608 used,  3209364 buff/cache
KiB Swap:  3145724 total,  3145724 free,        0 used.  4035756 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                   
 8398 user      20   0  0.103t 219560  29464 S   0.3  2.7   0:03.79 java                          
На графике jvisualvm
Размер использующейся в Heap памяти (Resident memory) остался почти таким же, как и при предыдущем запуске - около 20 Mb.

Размер выделенной под heap Commited memory сразу после запуска составляет 512Mб. С точки зрения JVM ключ -Xms указывает, какой размер Heap должен быть выделен при старте JVM. С точки зрения OC, виртуальное адресноге пространство памяти процесса JVM, равное 512m, должно быть зарезервировано в памяти ОС.

 JVM смогла запуститься без ошибок, несмотря на то, что заданная верхняя граница памяти Heap превышает количество памяти на сервере. То есть в виртуальном адресном пространстве памяти процесса было зарезервировано 100Gb, но пока эта память не используется, она никак не привязяна к физической памяти. -Xmx100G - это Reserved memory. Когда Heap (в моём примере он равен 512M) заполнится до такой степени, что JVM потребуется его увеличение, JVM запросит у ОС зарезервированную память (reserved memory).



В моём примере во время старта JVM под процесс выделяется 512mb (commited memory) и резервируется рамять в 100Gb (reserved memory). После увеличения размера heap (не графике справа) размер commited memory стал около 600 mb

среда, 12 октября 2016 г.

WNA Authentication. Потери UDP пакетов.

Решение проблемы с медленной аутентификацией (у нас доходило до  1 минуты) пользователей, использующих WNA.

Окружение:
Несколько доменом Windows.
Master Keytab для всех доменов.
Очень "большая" сеть.


В логах OAM-сервера WLS_OAM1.out:

KrbAsReqBuilder: PREAUTH FAILED/REQ, re-send AS-REQ
default etypes for default_tkt_enctypes: 17 23.
Added key: 23version: 0
Ordering keys wrt default_tkt_enctypes list
default etypes for default_tkt_enctypes: 17 23.
Added key: 23version: 0
Ordering keys wrt default_tkt_enctypes list
default etypes for default_tkt_enctypes: 17 23.
default etypes for default_tkt_enctypes: 17 23.
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
>>> KrbAsReq creating message
>>> KrbKdcReq send: kdc=uaad1sm.smua.local UDP:88, timeout=30000, number of retries =3, #bytes=236
>>> KDCCommunication: kdc=uaad1sm.smua.local UDP:88, timeout=30000,Attempt =1, #bytes=236
SocketTimeOutException with attempt: 1
>>> KDCCommunication: kdc=uaad1sm.smua.local UDP:88, timeout=30000,Attempt =2, #bytes=236
SocketTimeOutException with attempt: 2
>>> KDCCommunication: kdc=uaad1sm.smua.local UDP:88, timeout=30000,Attempt =3, #bytes=236
SocketTimeOutException with attempt: 3
>>> KrbKdcReq send: error trying uaad1sm.smua.local
java.net.SocketTimeoutException: Receive timed out
        at java.net.PlainDatagramSocketImpl.receive0(Native Method)
        at java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:146)
        at java.net.DatagramSocket.receive(DatagramSocket.java:817)
        at sun.security.krb5.internal.UDPClient.receive(NetClient.java:207)
        at sun.security.krb5.KdcComm$KdcCommunication.run(KdcComm.java:390)
        at sun.security.krb5.KdcComm$KdcCommunication.run(KdcComm.java:343)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.security.krb5.KdcComm.send(KdcComm.java:327)
        at sun.security.krb5.KdcComm.send(KdcComm.java:219)
        at sun.security.krb5.KdcComm.send(KdcComm.java:191)
        at sun.security.krb5.KrbAsReqBuilder.send(KrbAsReqBuilder.java:319)
        at sun.security.krb5.KrbAsReqBuilder.action(KrbAsReqBuilder.java:364)
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:735)
        at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:584)
        at sun.reflect.GeneratedMethodAccessor1782.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at javax.security.auth.login.LoginContext.invoke(LoginContext.java:762)

Необходимо добавить в конфиг krb5.conf:
[libdefaults]
udp_preference_limit = 1


Что это такое:
udp_preference_limit
When sending a message to the KDC, the library will try using TCP before UDP if the size of the message is above udp_preference_limit. If the message is smaller thanudp_preference_limit, then UDP will be tried before TCP. Regardless of the size, both protocols will be tried if the first attempt fails.

После этого в логах всё ок:
default etypes for default_tkt_enctypes: 17 23.
>>> KrbAsReq creating message
>>> KrbKdcReq send: kdc=uaad1sm.smua.local TCP:88, timeout=30000, number of retries =3, #bytes=153
>>> KDCCommunication: kdc=uaad1sm.smua.local TCP:88, timeout=30000,Attempt =1, #bytes=153
>>>DEBUG: TCPClient reading 177 bytes
>>> KrbKdcReq send: #bytes read=177
>>>Pre-Authentication Data:
         PA-DATA type = 11
         PA-ETYPE-INFO etype = 23, salt =

вторник, 19 апреля 2016 г.

Weblogic 12.2.1 WNA

После оновления weblogic с 12.1.3 до 12.2.1 внезапно перестала работать Windows Native Authentication.
Конфигурационные файлы при обновлении не менялись. Манипуляций с кейтабами не проводилось. 
Сообщения в логах:

<Debug> <SecurityAtn> <sm-ecm-idm-test1.moscow.sportmaster.ru> <tst_1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <6d5d0986-0aaa-4118-ace1-d9a310c02383-00000021> <1454403844063> <[severity-value: 128] [rid: 0] [partition-id: 0] [partition-name: DOMAIN] > <BEA-000000> <Failed to create GSSContext for HTTP/sm-ecm-idm-test1.moscow.sportmaster.ru@GKSM.LOCAL
GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos credentails)
at sun.security.jgss.krb5.Krb5AcceptCredential.getInstance(Krb5AcceptCredential.java:87)

Общение с техподдержкой результатов не дало.
На данный момент найден воркэраунд - перегенерить кейтаб.

Для Weblogic 12.1.3 кейтаб генерировался по следующей схеме.
FQDN: someserver.somedomain
UserName: someserver_srv
UserPrincipalName: HTTP/someserver_srv@ADDOMAIN
SPN: someserver.somedomain

То есть имя сервера обычно не совпадает с именем учётки, которая создаётся для кейтаба.
Кейтаб генерируется безявного указания UserPrincipalName.
После генерации кеутаба добавляется spn, соответствующий FQDN.

Для Weblogic 12.2.1 это схема почему-то не работает. Поддержка комментирует это как "изменения, связанные с новой версией JVM", что есть глупость.

рабочий воркэраунд:
FQDN: someserver.somedomain
UserName: someserver_srv
UserPrincipalName: HTTP/someserver@ADDOMAIN

То есть при генерации кейтаба надо явно указать UserPrincipalName = hostname.
Если этого не сделать, бесполезно потом добавлять правильные SPN. Работать всё равно не будет.



среда, 27 января 2016 г.

Embedded Ldap Error (conn=1 op=0 RESULT err=0 tag=0 nentries=0 etime=0)

После одного из внезапных ребутов сервера возникли проблемы со свтроенным LDAP-каталогом сервера Weblogic.
Обнаружилось по всё замедляющейся работе сервера приложений.

Netstat показал, что к серверу wsm-pm открыто более 37 000 соединений.
Netstat -ntp | grep 8003 | wc -l
34872
В логах самого сервера сообщений об ошибках не наблюдалось, но в LDAP-логи
${DOMAIN_HOME}/servers/${servername}/data/ldap/log со скоростью несколько сотен в секунду добавлялись вот такие записи:
[20/Jan/2016 11:43:12 MSK] conn=1 op=0 BIND dn="cn=Admin" method=0 version=3
[20/Jan/2016 11:43:12 MSK] conn=1 op=0 RESULT err=0 tag=0 nentries=0 etime=0
Лечится удалением папки  ${DOMAIN_HOME}/servers/${servername}/data/ldap
и ${DOMAIN_HOME}/servers/${servername}/data/store
Они отреплицируются с AdminServer-а после того, как ManagedServer будет перезапущен.

Unpublished kernel bug 21683388

Сегодня нашёл ноту на металинке с подтверждением важного исправления для многих своих установок. Unpublish kernel bug 21683388.
Баг исправлен в ноябре прошлого года.
Проблема проявлялется в падении ядра при использовании связки
Oracle Linux 6 (kernel 3.8.13-98.6.1) или ниже + HugePages
JVM с ключом -XX:+UseLargePages

В такой конфигурации после нескольких часов работы сервер уходил в ребут с примерно таким сообщением об ошибке:

------------[ cut here ]------------
Jan 19 11:17:33 serverName kernel: WARNING: at lib/list_debug.c:33 __list_add+0xbe/0xd0()
Jan 19 11:17:33 serverName kernel: Hardware name: ProLiant BL460c Gen9
Jan 19 11:17:33 serverName kernel: list_add corruption. prev->next should be next (ffff883f174af828), but was ffff883f209a7e20. (prev=ffff883f218688c0).
Jan 19 11:17:33 serverName kernel: Modules linked in: mptctl mptbase autofs4 cpufreq_ondemand pcc_cpufreq bonding ipv6 scsi_dh_alua sg serio_raw ses enclosure hpilo hpwdt coretemp hwmon freq_table mperf intel_powerclamp kvm ghash_clmulni_intel microcode pcspkr ioatdma dca shpchp ext4 jbd2 mbcache dm_round_robin sd_mod crc_t10dif usb_storage aesni_intel ablk_helper cryptd lrw aes_x86_64 xts gf128mul qla2xxx scsi_transport_fc scsi_tgt crc32c_intel be2net be2iscsi bnx2i cnic uio cxgb4i cxgb4 xhci_hcd cxgb3i libcxgbi cxgb3 mdio libiscsi_tcp qla4xxx wmi iscsi_boot_sysfs libiscsi scsi_transport_iscsi dm_multipath dm_mirror dm_region_hash dm_log dm_mod
Jan 19 11:17:33 serverName kernel: Pid: 2888, comm: java Tainted: G        W    3.8.13-68.3.4.el6uek.x86_64 #2
Jan 19 11:17:33 serverName kernel: Call Trace:
Jan 19 11:17:33 serverName kernel: [<ffffffff8105e83f>] warn_slowpath_common+0x7f/0xc0
Jan 19 11:17:33 serverName kernel: [<ffffffff8105e936>] warn_slowpath_fmt+0x46/0x50
Jan 19 11:17:33 serverName kernel: [<ffffffff8129bf7e>] __list_add+0xbe/0xd0
Jan 19 11:17:33 serverName kernel: [<ffffffff81173e8e>] region_chg+0x7e/0x100
Jan 19 11:17:33 serverName kernel: [<ffffffff81173f72>] vma_needs_reservation+0x62/0xb0
Jan 19 11:17:33 serverName kernel: [<ffffffff81174c52>] alloc_huge_page+0x62/0x2c0
Jan 19 11:17:33 serverName kernel: [<ffffffff811308fe>] ? find_get_page+0x1e/0xa0
Jan 19 11:17:33 serverName kernel: [<ffffffff81175390>] hugetlb_no_page+0xa0/0x360
Jan 19 11:17:33 serverName kernel: [<ffffffff81176797>] hugetlb_fault+0x337/0x430
Jan 19 11:17:33 serverName kernel: [<ffffffff8115d9e8>] __handle_mm_fault+0x168/0x1f0
Jan 19 11:17:33 serverName kernel: [<ffffffff81098090>] ? wake_up_state+0x10/0x20
Jan 19 11:17:33 serverName kernel: [<ffffffff8115db22>] handle_mm_fault+0xb2/0x1a0
Jan 19 11:17:33 serverName kernel: [<ffffffff8159ed37>] __do_page_fault+0x217/0x4d0
Jan 19 11:17:33 serverName kernel: [<ffffffff810bf6f0>] ? do_futex+0x100/0x1b0
Jan 19 11:17:33 serverName kernel: [<ffffffff8159968d>] ? __schedule+0x3fd/0x720
Jan 19 11:17:33 serverName kernel: [<ffffffff810bf81b>] ? sys_futex+0x7b/0x180
Jan 19 11:17:33 serverName kernel: [<ffffffff8159effe>] do_page_fault+0xe/0x10
Jan 19 11:17:33 serverName kernel: [<ffffffff8159b498>] page_fault+0x28/0x30
Jan 19 11:17:33 serverName kernel: ---[ end trace 71a6e99ef3a2ba66 ]---
Лечится обновлением ядра.

вторник, 10 ноября 2015 г.

Tomcat. Хранение пароля пользователей в зашифрованном виде.

1. Отредактировать ./webapps/manager/WEB-INF/web.xml

Указать метод аутентификации DIGEST
<login-config>
   <auth-method>DIGEST</auth-method>
   <realm-name>Tomcat Manager Application</realm-name>
 </login-config>

2. Отредактировать ./conf/server.xml.
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
 добавить digest="md5"
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" digest="md5"/>
3. Сгенерировать
digest -a md5 username:myrealm:mypassword
В случае приложения manager:
digest -a md5 manager-admin:Tomcat\ Manager\ Application:Welcome1
manager-admin:Tomcat Manager Application:7e1111111111111111111141d7333df2b0
4. Отредактировать файл ./conf/tomcat-users.xml

<user username="manager-admin" password="7e111111111111111111141d7333df2b0" roles="manager-gui,manager-script,manager-jmx"/>


пятница, 7 августа 2015 г.

Установка SOA Server 12c. TriggerWithRescheduleError NoClassDefFoundError

Один из необходимых шагов после установки SOA Suite 12c - отредактировать файл setDominEnv.sh, добавив в переменную CLASSPATH необходимую библиотеку. Например. вот так:
PRE_CLASSPATH="/opt/oracle/middleware/fmw_12.1.3/soa/soa/modules/oracle.bpm.runtime.classloader-util.jar:${PRE_CLASSPATH}"
export PRE_CLASSPATH
Если этого не сделать. в логах можно наблюдать вот такое сообщение:

<Error> <oracle.bpm.engine> <BEA-000000> <post deploy failed for component TransferToArchive
javax.ejb.EJBException: EJB Exception: : java.lang.NoClassDefFoundError: oracle/bpm/runtime/quartz/trigger/TriggerWithReschedule

вторник, 21 июля 2015 г.

OVD NO-SSL Listener

Oracle рекомендует отказаться от NIO для листенера, не исползующего SSL, в случае, если LDAP-операции занимают необычно долгое время (до 60 сек.) 
Как правило, этот листенер слушает на порту 6501.
Конфигурационный файл:
$ORACLE_INSTANCE/config/OVD/ovd1/listener.os_xml
Необходимо добавить тэг <useNIO>false</useNIO> так же, как в SSL листенере 


четверг, 4 июня 2015 г.

Oracle Access Manager BasicAuth&WNA

Недвно получили проблему для следующего окружения:
Oracle Access Manager занимается аутентификацией пользователей в некотором домене.
В качестве источника учётных данных пользователей используется AD.
Аутентификация проходит по алгоритму: WNA, если возможно. Если WNA не поддерживается клиентом, используется Basic Auth.

После установки OAM BP3 перестала работать Basic аутентификация.
Оказалось, в readme патча отсутствуют необходмые дополнительные шаги:
1. В файле  oam-config.xml заменить  DEFAULT на BASIC
<Setting Name="WNAOptions" Type="htf:map">'        <Setting Name="HandleNTLMResponse" Type="xsd:string">DEFAULT</Setting>

2. В том же файле в ноду <Setting Name="credCollectReqRespHandlers" Type="htf:map"> 
добавить строку

        <Setting Name="WNA" Type="xsd:string">oracle.security.am.engines.enginecontroller.plugin.WNAReqRespHandler</Setting>'

3. В файле config.xml в ноду <security-configuration>'
добавить строку 
<enforce-valid-basic-auth-credentials>false</enforce-valid-basic-auth-credentials>
после элемента <node-manager-password-encrypted>.