1

My linux free memory is 4942356kb before I run a java application.my StartUp paramter use -Xmx2048m and -Xms2048m to make the max heap memory and initial heap memory to be 2G.But I find that after I start up the application,my linux system free memory is decreasing step by step , instead of total 2G memory was consumed after starting up.Anyone can tell me the reason and mechanism?

And another question , My jvm startup parameter is -XX:+PrintGCDetails -Xss512k -Xmx4096m -Xms4096m -Xloggc:gc_01221859.log , and free memory before start up is 5G, after 1 hour , I find that this application has already 14,053 threads .Obviously , 14053 * 512k = 7195136 = 7.2G stack memory is consumed, which is obvious larger than system free memory and total memory.Anyone could explain this for me ?

when number of thred is 14053 , I use jcmd <pid> VM.native_memory summary to dump the Native memory , it output:

Native Memory Tracking:

Total:  reserved=8688195KB,  committed=8645103KB

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

-                     Class (reserved=5997KB, committed=5997KB)
                            (classes #8918)
                            (malloc=5997KB, #7418)

-                    Thread (reserved=5815888KB, committed=5815888KB)
                            (thread #11139)
                            (stack: reserved=5752332KB, committed=5752332KB)
                            (malloc=35936KB, #44562)
                            (arena=27620KB, #22266)

-                      Code (reserved=51385KB, committed=8293KB)
                            (malloc=1465KB, #2689)
                            (mmap: reserved=49920KB, committed=6828KB)

-                        GC (reserved=85657KB, committed=85657KB)
                            (malloc=5889KB, #155)
                            (mmap: reserved=79768KB, committed=79768KB)

-                  Compiler (reserved=294KB, committed=294KB)
                            (malloc=196KB, #400)
                            (arena=98KB, #2)

-                  Internal (reserved=52609KB, committed=52609KB)
                            (malloc=52609KB, #283728)

-                    Symbol (reserved=13406KB, committed=13406KB)
                            (malloc=10010KB, #98269)
                            (arena=3396KB, #1)

-           Memory Tracking (reserved=301363KB, committed=301363KB)
                            (malloc=301363KB, #28396)

-        Pooled Free Chunks (reserved=179933KB, committed=179933KB)
                            (malloc=179933KB)

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

the top output:

top - 18:47:02 up 397 days, 26 min,  1 user,  load average: 3.68, 3.46, 2.58
Tasks: 164 total,   1 running, 163 sleeping,   0 stopped,   0 zombie
Cpu(s):  2.5%us,  0.6%sy,  0.0%ni, 96.7%id,  0.1%wa,  0.0%hi,  0.0%si,  0.1%st
Mem:   5990984k total,  5144764k used,   846220k free,    11564k buffers
Swap:        0k total,        0k used,        0k free,   132748k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
11513 wuchang   20   0 12.1g 3.7g  15m S 188.8 64.9  41:46.42 java              
 1264 wuchang   20   0 17116 1240  900 R  1.8  0.0   0:00.02 top                
    1 root      20   0 19232  364   84 S  0.0  0.0   0:02.57 init   

the free output is:

             total       used       free     shared    buffers     cached
Mem:       5990984    5786744     204240          0      12012     134092
-/+ buffers/cache:    5640640     350344
Swap:            0          0          0

I have wrote a very simple java code whose work is just create thread:

public class CreateThread {
    private static int threadNumber = 0;

    public static void main(String[] args) {
        while (true) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    System.out.println("Thread " + threadNumber++);
                    while(true){
                        try {
                            Thread.sleep(20000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }

            }).start();
        }
    }
}

After wrapper it into a jar file run it in linux like this:

java -Xss512k -jar CreateThread.jar > /home/wuchang/test

it created totally 32313 threads before report :

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:714)
at CreateThread.main(CreateThread.java:22)

And another question ,why the error is OutOfMemory instead of StackOverflow?

Some limit of my linux system thread is :

[wuchang@hz10-45-88 ~]$ cat /proc/sys/kernel/threads-max 
93335
[wuchang@hz10-45-88 ~]$ ulimit -u
46667

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------


UPDATE 1 : Everytime I run my java application with different startup parameters, including three cases:

case 1: -Xss512k -Xmx4096m -Xms4096m
case 2: -Xss512k -Xmx2048m -Xms2048m
case 3: -Xss256k -Xmx2048m -Xms2048m

of course, since my application is a pressure test, after a period of time ,the process will be killed automically by OS.I have record the last top output before it is killed below:

case 1:
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
18136 wuchang   20   0 15.4g 4.3g 6456 S 99.3 75.0  36:16.22 java   
case 2:
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
 9689 wuchang   20   0 15.0g 4.2g  14m S 98.6 73.0  55:36.62 java       
case 3:
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
 8237 wuchang   20   0 10.1g 4.2g 9284 S 100.6 74.0  60:43.95 java 

each time before I run start up the process, system free memory is about 5G. from above output , each time the VIRT vary a lot , but RES stay approximately the same. So ,my additional question is:

  1. What does the MAX VIRT depend on before my process is killed by OS?

  2. How can I estimate the maximum thread according to 1)OS free memory before startup up and 2)the JVM startup parameter?

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------


UPDATE 2 :

I have run the code provided by @Ivan:

public class CreateThread {
  private static int threadNumber = 0;

  public static int doRecursiveCall(int i) throws StackOverflowError {
      return doRecursiveCall(++i);
  }

  public static void warmupNativeStack() {
      int sideEffect;
      try {
          sideEffect = doRecursiveCall(0);
      } catch (StackOverflowError ignored) {
          return;
      }
      System.out.println("Never happend  " + sideEffect);
  }

  public static void main(String[] args) {
      while (true) {
          new Thread(new Runnable() {

              @Override
              public void run() {
                  warmupNativeStack();
                  System.out.println("Thread " + threadNumber++);
                  while (true) {
                      try {
                          Thread.sleep(20000);
                      } catch (InterruptedException e) {
                          Thread.currentThread().interrupt();
                      }
                  }
              }
          }).start();
      }
    }
}

The result is:

java -Xss512k -Xmx2048m -Xms2048m -jar CreateThread.jar
totally 8600 threads are created.before exit,the max VIRT is 8.7G and max RSS is 4.5G

java -Xss256k -Xmx2048m -Xms2048m -jar CreateThread.jar
totally 16780 threads are created.before exit,the max VIRT is 8.7G and max RSS is 4.6G

Experiment show that in this case, the max VIRT and RSS has nothing to do with jvm startup parameter,they stay the same.So ,according to the experiment result of UPDATE 1 AND UPDATE 2, I guess, the reason that my app is killed by OS may be that the RSS memory has reached the limit ,instead of the number of thread or the total VIRT , right?

wuchang
  • 3,003
  • 8
  • 42
  • 66

1 Answers1

2

By default JVM touches pages incrementally during application execution. In order to change this behavior use the following option -XX:+AlwaysPreTouch. In this case JVM pre-touches heap during JVM initialization(every page of the heap is demand-zeroed).

Also don't forget about JVM native memory

Update:

Most likely your memory is swapped. You can check swap usage by using the following instructions.

Update 2:

In this case you're dealing with overcommitment. Memory overcommit is a OS feature that allows to use more memory space than the physical machine actually has. Native stacks are lazy enough to avoid of touching backed physical memory. So as a result you have 12.1g of virtual memory and 3.7g of RSS. For further more detailed analysis, you can use pmap -x <java pid>.

I have wrote a very simple java code whose work is just create thread

That's why the memory allocated for the threads was not used. Just do something useful in your threads. For example:

public class CreateThread {
  private static int threadNumber = 0;

  public static int doRecursiveCall(int i) throws StackOverflowError {
      return doRecursiveCall(++i);
  }

  public static void warmupNativeStack() {
      int sideEffect;
      try {
          sideEffect = doRecursiveCall(0);
      } catch (StackOverflowError ignored) {
          return;
      }
      System.out.println("Never happend  " + sideEffect);
  }

  public static void main(String[] args) {
      while (true) {
          new Thread(new Runnable() {

              @Override
              public void run() {
                  warmupNativeStack();
                  System.out.println("Thread " + threadNumber++);
                  while (true) {
                      try {
                          Thread.sleep(20000);
                      } catch (InterruptedException e) {
                          Thread.currentThread().interrupt();
                      }
                  }
              }
          }).start();
      }
    }
}

why the error is OutOfMemory instead of StackOverflow?

Actually, you're in luck because in real life everything ends with OOM killer. In your case a new Java thread is requested through OS. The OS tries to create a new native thread which requires memory to be allocated for the thread but allocation failed due to the lack of physical memory. In real life your java application will be killed by Linux kernel(OOM killer). Stack overflow is used for other purposes(see another answer)

What does the MAX VIRT depend on before my process is killed by OS?

See Virtual Memory size on Linux

How can I estimate the maximum thread according the OS free memory before startup up and the JVM startup parameter?

It depends on many factors and JVM parameters don't play any role. For example you have to know the maximum depth of the call stack in your application - check thread count with your and with mine examples.

Community
  • 1
  • 1
Ivan Mamontov
  • 2,874
  • 1
  • 19
  • 30
  • thank you .I user top command , it shows that my swap size is zero.Then ,what could make my total stack memory is larger than total system free memory? – wuchang Jan 25 '16 at 09:25
  • 1
    Please provide output from 'free' and internal memory usage `-XX:NativeMemoryTracking=summary`. – Ivan Mamontov Jan 25 '16 at 09:29
  • Thank you so much for you detailed explanation.I have some additional description in UPDATE 1.Is it possible to estimate the max thread number before I run the process, according the system free memory before startup and the jvm startup parameter? – wuchang Jan 26 '16 at 11:26