Let's run a simple java
java -XshowSettings:vm -version VM settings:
    Max. Heap Size (Estimated): 3.45G
    Ergonomics Machine Class: server
    Using VM: Java HotSpot(TM) 64-Bit Server VM
java version "1.8.0_162"
Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed modeAnd now let's run the same thing in a container:
docker run openjdk:8-jre java -XshowSettings:vm -versionNothing really change in the container :)
VM settings:
    Max. Heap Size (Estimated): 3.45G
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM
openjdk version "1.8.0_162"
OpenJDK Runtime Environment (build 1.8.0_162-8u162-b12-1~deb9u1-b12)
OpenJDK 64-Bit Server VM (build 25.162-b12, mixed mode)Now we going to try to limit the memory of the JVM
docker run -m 128MB openjdk:8-jre java -XshowSettings:vm -versionOk again we have the same result, hum...
VM settings:
    Max. Heap Size (Estimated): 3.45G
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM
openjdk version "1.8.0_162"
OpenJDK Runtime Environment (build 1.8.0_162-8u162-b12-1~deb9u1-b12)
OpenJDK 64-Bit Server VM (build 25.162-b12, mixed modeWhy the JVM see those 3.45G? This is the Ergonomics : https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/ergonomics.html
We can read :
A class of machine referred to as a server-class machine has been defined as a machine with the following:
    2 or more physical processors
    2 or more GB of physical memory
On server-class machines, the following are selected by default:
    Throughput garbage collector
    Initial heap size of 1/64 of physical memory up to 1 GB
    Maximum heap size of 1/4 of physical memory up to 1 GB
docker run openjdk:8-jre java -Xmx128m -XshowSettings:vm -versionThis looks better, the jvm set the max size to the value
VM settings:
    Max. Heap Size: 128.00M
    Ergonomics Machine Class: server
...But it's not really easy to build/ or configure Xmx when you deploy your application to k8s/Swarm/Mesos...
The JDK 9 include an option to include a partial support of cgroups, it must be activate with UnlockExperimentalVMOptions / UseCGroupMemoryLimitForHeap. Those are backported to the JDK 8 1.8.0_131+
docker run -m 128MB openjdk:8-jre java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -versionThis looks better, the jvm set the max size to the value
VM settings:
    Max. Heap Size (Estimated): 57.00M
...With more memory:
docker run -m 1GB openjdk:8-jre java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -versiondocker run -m 1GB openjdk:10-jre java -XshowSettings:vm -versionOnly 228MB are used :
VM settings:
    Max. Heap Size (Estimated): 228.00M
...You can tell the JVM to use more memory for HEAP with -XX:MaxRAMFraction (default is 4):
docker run -m 1GB openjdk:8-jre java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2 -XshowSettings:vm -versionThe JVM use available memory/MaxRAMFraction as max heap. Using -XX:MaxRAMFraction=1 we are using almost all the available memory as max heap.
docker run -d simple-springboot-jdk8docker statsCONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %
137a549714d4        focused_bose        0.00%               44.2MiB / 15.52GiB    0.28%
24d624be19f2        optimistic_curie    0.17%               420.4MiB / 15.52GiB   2.65%docker run -d -m 256MB simple-springboot-jdk8docker statsSwap!!!
docker run -d -m 256MB simple-springboot-jdk8 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2 -jar app.jarNo swap!!
### OOM Killer
Who is this bad guy?
Oom killer will kill the process who consume too much resource.
It can be seeing in action :
journalctl -f _TRANSPORT=kernelAnd then run
docker run -m 50MB  jvmtest HeapTestYou should read something like:
 kernel: Memory cgroup out of memory: Kill process 20184 (java) score 1119 or sacrifice child
And you can also check the state of the previous container and search the OOMKilled field.
docker container inspect $(docker container ls -lq) or directly:
docker container inspect $(docker container ls -lq) --format={{.State.OOMKilled}}In docker you can reduce the cpu use of container by:
- --cpus=
- --cpuset-cpus=
- --cpuset-shares=
- --cpu-period & --cpu-quota
docker run --cpuset-cpus=0  toolbox.jdk9 CpuLoadTestAll Java 8,9 & 10 will be limited in cpu use with Cgroups, but the JVM is not aware of this. So the JVM isn't optimize for the available cpu (container) but for the number of cpu in the host.
### --cpus
docker run --cpus=1 toolbox.jdk8 CpuTest
docker run --cpus=1 toolbox.jdk9 CpuTest
docker run --cpus=1 toolbox.jdk10 CpuTestIt failed for JDK8 & 9.
### --cpuset-cpus
docker run --cpuset-cpus=0 toolbox.jdk8 CpuTest
docker run --cpuset-cpus=0 toolbox.jdk9 CpuTest
docker run --cpuset-cpus=0 toolbox.jdk10 CpuTestIt works on JDK8 & 9 & 10!
### --cpu-shares
docker run --cpu-shares=1024 toolbox.jdk8 CpuTest
docker run --cpu-shares=1024 toolbox.jdk9 CpuTest
docker run --cpu-shares=1024 toolbox.jdk10 CpuTestFailed for all, but it's not
### --cpu-period & --cpu-quota
docker run --cpu-period=100000 --cpu-quota=500000 toolbox.jdk8 CpuTest
docker run --cpu-period=100000 --cpu-quota=500000 toolbox.jdk9 CpuTest
docker run --cpu-period=100000 --cpu-quota=500000 toolbox.jdk10 CpuTestOnce again failed for JDK8 & 9.
docker run --cpus=1 openjdk:8-jre java -XshowSettings:vm -XX:+PrintFlagsFinal -version | grep -Ei "MaxRam|MaxHeapSize|ParallelGCThreads|CICompilerCount|UseSerialGC|UseParallelGC|tenuring|UseG1GC|UseConcMarkSweepGC"intx CICompilerCount                          := 4                                   {product}
uintx ParallelGCThreads                         = 8                                   {product}
bool UseConcMarkSweepGC                        = false                               {product}
bool UseG1GC                                   = false                               {product}
bool UseParallelGC                            := true                                {product}
bool UseSerialGC                               = false                               {product}
What does the brand new JDK10?
docker run -m 128MB openjdk:10-jre java -XshowSettings:vm -versionLooks Like it's work!!!
VM settings:
    Max. Heap Size (Estimated): 61.88M
    Using VM: OpenJDK 64-Bit Server VM
openjdk version "10" 2018-03-20
OpenJDK Runtime Environment (build 10+46-Debian-2)
OpenJDK 64-Bit Server VM (build 10+46-Debian-2, mixed mode)More information
docker run openjdk:10-jre java -XshowSettings:vm  -XX:+PrintFlagsFinal -version | grep -Ei "MaxRam|MaxHeapSize|ParallelGCThreads|CICompilerCount|UseSerialGC|UseParallelGC|tenuring|UseG1GC|UseConcMarkSweepGC"     intx CICompilerCount                          = 4                                        {product} {ergonomic}
     bool CICompilerCountPerCPU                    = true                                     {product} {default}
    uintx InitialTenuringThreshold                 = 7                                        {product} {default}
   size_t MaxHeapSize                              = 4167041024                               {product} {ergonomic}
 uint64_t MaxRAM                                   = 137438953472                          {pd product} {default}
    uintx MaxRAMFraction                           = 4                                        {product} {default}
   double MaxRAMPercentage                         = 25.000000                                {product} {default}
    uintx MaxTenuringThreshold                     = 15                                       {product} {default}
     uint ParallelGCThreads                        = 8                                        {product} {default}
     bool UseConcMarkSweepGC                       = false                                    {product} {default}
     bool UseG1GC                                  = true                                     {product} {ergonomic}
     bool UseParallelGC                            = false                                    {product} {default}
     bool UseSerialGC                              = false                                    {product} {default}
VM settings:
    Max. Heap Size (Estimated): 3.88G
    Using VM: OpenJDK 64-Bit Server VM
openjdk version "10" 2018-03-20
OpenJDK Runtime Environment (build 10+46-Debian-2)
OpenJDK 64-Bit Server VM (build 10+46-Debian-2, mixed mode)
``̀
And if we limit the memory to 128MB :
```bash
docker run -m 128MB openjdk:10-jre java -XshowSettings:vm -XX:+PrintFlagsFinal -version | grep -Ei "MaxRam|MaxHeapSize|ParallelGCThreads|CICompilerCount|UseSerialGC|UseParallelGC|tenuring|UseG1GC|UseConcMarkSweepGC"
     intx CICompilerCount                          = 4                                        {product} {ergonomic}
     bool CICompilerCountPerCPU                    = true                                     {product} {default}
    uintx InitialTenuringThreshold                 = 7                                        {product} {default}
   size_t MaxHeapSize                              = 67108864                                 {product} {ergonomic}
 uint64_t MaxRAM                                   = 137438953472                          {pd product} {default}
    uintx MaxRAMFraction                           = 4                                        {product} {default}
   double MaxRAMPercentage                         = 25.000000                                {product} {default}
    uintx MaxTenuringThreshold                     = 15                                       {product} {default}
     uint ParallelGCThreads                        = 0                                        {product} {default}
     bool UseConcMarkSweepGC                       = false                                    {product} {default}
     bool UseG1GC                                  = false                                    {product} {default}
     bool UseParallelGC                            = false                                    {product} {default}
     bool UseSerialGC                              = true                                     {product} {ergonomic}
VM settings:
    Max. Heap Size (Estimated): 61.88M
    Using VM: OpenJDK 64-Bit Server VM
openjdk version "10" 2018-03-20
OpenJDK Runtime Environment (build 10+46-Debian-2)
OpenJDK 64-Bit Server VM (build 10+46-Debian-2, mixed mode)Check the GC configuration, and the thread numbers for CICompiler, GC Threads
y0an@orion   docker run --memory 128MB heapeater -Xmx128m -jar app.jar
y0an@orion   docker run --memory 128MB --memory-swap 128MB heapeater -jar app.jar
watch swap:
watch -n1 cat /sys/fs/cgroup/memory/docker/9c86bb6e2da634b8de299ce87da7d4ff8cda0b2c4f5d9edf1c44f75224aeb58a/memory.stat ## OOM Killer
Who is this bad guy?
Oom killer will kill the process who consume too much resource.
It can be seeing in action :
journalctl -f _TRANSPORT=kernelAnd then run
docker run -m 50MB  jvmtest HeapTestYou should read something like:
 kernel: Memory cgroup out of memory: Kill process 20184 (java) score 1119 or sacrifice child
And you can also check the state of the previous container and search the OOMKilled field.
docker container inspect $(docker container ls -lq) or directly:
docker container inspect $(docker container ls -lq) --format={{.State.OOMKilled}}Inliner
jstatd -p 1099 -J-Djava.security.policy=<(echo 'grant codebase "file:${java.home}/../lib/tools.jar" {permission java.security.AllPermission;};')
``̀
Mesurer la swap container
Mesurer la conso jvm global
https://docs.docker.com/config/containers/resource_constraints/#--memory-swap-details
docker run -m 100MB --memory-swap=100MB openjdk:8-jre java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm
-version
## More
Curious about JVM and options? Check this:
```bash
java -XX:+AggressiveOpts -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version | wc -l-XX:+PrintFlagsFinal -XX:+PrintGCDetails
docker run openjdk:8-jre java -XshowSettings:vm -XX:+PrintFlagsFinal -version | grep -Ei "MaxRam|MaxHeapSize|ParallelGCThreads|CICompilerCount|UseSerialGC|UseParallelGC|tenuring|UseG1GC|UseConcMarkSweepGC"
Let's start a simple Spring Boot Project
docker run  simple-springboot -jar app.jarAnd check the memory size
docker stats CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT  
942291a20d4f        silly_colden        0.13%               365.6MiB / 15.52GiBdocker run -m 365MB simple-springboot -Xmx365m  -jar app.jardocker run -m 160MB simple-springboot -Xmx160m  -jar app.jar