1. Definitions
Java Virtual Machine Stacks
- The memory space required for each thread is called virtual machine stack
- Each stack consists of multiple stack frames, corresponding to the memory occupied by each method call
- Each thread can only have one active stack frame, corresponding to the currently executing method
2. Presentation
public class Main { public static void main(String[] args) { method1(); } private static void method1() { method2(1, 2); } private static int method2(int a, int b) { int c = a + b; return c; } }
Process analysis:
Let's interrupt to Debug and take a look at the process of method execution:
You can see from the console that the methods in the main class conform to the characteristics of the stack when entering the virtual machine stack
3. Problem analysis
3.1. Does garbage collection involve stack memory?
unwanted. Because the virtual machine stack is composed of stack frames, after the method is executed, the corresponding stack frame will be popped out of the stack. Therefore, there is no need to recycle memory through garbage collection mechanism.
3.2. Is the larger the stack memory allocation, the better?
no Because the physical memory is certain, the larger the stack memory, the more recursive calls can be supported, but the fewer threads can be executed.
For example, if the physical memory is 500m (assuming), if the stack memory that a thread can allocate is 2M, there can be 250 threads. If a thread allocates 5M of stack memory, at most 100 threads can execute at the same time! Therefore, a large stack memory partition will only reduce the number of runnable threads.
3.3. Are local variables in methods thread safe?
Case 1:
Case 2: if you change int x to static, there will be a thread safety problem:
It can be concluded from the figure that if local variables are static and can be shared by multiple threads, there is a thread safety problem. If it is non static, exists only within the scope of a method and is private to the thread, it is thread safe!
Let's take another example:
/** * Thread safety of local variables */ public class Demo02 { public static void main(String[] args) {// Main function main thread StringBuilder sb = new StringBuilder(); sb.append(4); sb.append(5); sb.append(6); new Thread(() -> {// Thread newly created thread m2(sb); }).start(); } public static void m1() { // As a local variable inside method m1(), sb is thread private -- > thread safe StringBuilder sb = new StringBuilder(); sb.append(1); sb.append(2); sb.append(3); System.out.println(sb.toString()); } public static void m2(StringBuilder sb) { // sb is a parameter passed outside the method m2(), and sb is not within the scope of the method m2() // Not thread private -- > non thread safe sb.append(1); sb.append(2); sb.append(3); System.out.println(sb.toString()); } public static StringBuilder m3() { // As a local variable in method m3(), sb is thread private StringBuilder sb = new StringBuilder();// sb is a variable of reference type sb.append(1); sb.append(2); sb.append(3); return sb;// However, the method m3() returns sb, which escapes the scope of the method m3(), and Sb is a variable of reference type // Other threads can also get the -- > non thread safe value of this variable // If sb is a non reference type, that is, a basic type (int/char/float...) variable, thread safety will not exist after escaping the scope of m3() } }
Summary:
- If local variables within a method do not escape the scope of the method, it is thread safe
- If a local variable references an object (for example, the StringBuilder above refers to an object) and escapes the scope of the method, thread safety needs to be considered
- If a local variable is just a basic type variable (no reference object) and escapes the scope of the method, there is no thread safety problem
3.4. Stack memory overflow
Java.lang.stackOverflowError stack memory overflow
- In the virtual machine stack, too many stack frames (infinite recursion) lead to stack memory overflow, which is common!
- The memory occupied by each stack frame is too large (the memory of one / several stack frames directly exceeds the maximum memory of the virtual machine stack). This is rare!
As shown in the figure, there are too many stack frames in the stack:
demonstration
/** * Demonstrate stack memory overflow java.lang.StackOverflowError * -Xss256k */ public class Demo1_2 { private static int count; public static void main(String[] args) { try { method1(); } catch (Throwable e) { e.printStackTrace(); System.out.println(count); } } private static void method1() { count++; method1(); } }
Execution times:
When we reduce the virtual machine stack memory to the specified 256k, run Demo1 again_ 2, the maximum number of stack frames in the stack will be 2928, which is far less than the original 23040!
3.5. Thread diagnosis_ CPU usage too high
When running some programs in Linux environment, it may lead to excessive CPU consumption. At this time, it is necessary to locate threads that occupy too much CPU
package com.stack; /** * Demo cpu usage too high */ public class Demo1_16 { public static void main(String[] args) { new Thread(null, () -> { System.out.println("1..."); while (true) { } }, "thread1").start(); new Thread(null, () -> { System.out.println("2..."); try { Thread.sleep(1000000L); } catch (InterruptedException e) { e.printStackTrace(); } }, "thread2").start(); new Thread(null, () -> { System.out.println("3..."); try { Thread.sleep(1000000L); } catch (InterruptedException e) { e.printStackTrace(); } }, "thread3").start(); } }
-
top command to see which process is occupying too much CPU
-
ps H -eo pid, tid (thread id),% cpu | grep the process number just found through top. Use the ps command to further check which thread occupies too much CPU
-
Jstack process id is located by comparing the nid of the thread in the process with the tid just seen through the ps command. Note that the thread id found by jstack is hexadecimal and needs to be converted
3.6. Thread diagnosis_ There is no result
package com.stack; /** * Demo thread deadlock */ class A{}; class B{}; public class Demo1_3 { static A a = new A(); static B b = new B(); public static void main(String[] args) throws InterruptedException { new Thread(()->{ synchronized (a) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (b) { System.out.println("I got it a and b"); } } }).start(); Thread.sleep(1000); new Thread(()->{ synchronized (b) { synchronized (a) { System.out.println("I got it a and b"); } } }).start(); } }