ReZero's Utopia.

Java tools

Word count: 1.4kReading time: 5 min
2021/05/01 Share

参数附录

1
2
3
4
5
6
-Xss128K 栈内存大小: 局部变量表膨胀对应的方法栈帧就大从而消耗的栈内存就大进而影响到递归次数
-Xmx 堆空间最大限制
-Xms 初始堆内存, 可配置同Xmx大小
-Xmn 年轻代大小
-XX:NewRatio=4:设置年轻代[包括Eden和两个Survivor区]与年老代的比值
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值

直接内存申请上弱于堆内存,但读写快,因此相比堆内存,适用于申请次数少,但是读写次数多的场景

简介

Java线程堆栈是虚拟机中线程(包括锁) 状态的一个瞬间快照, 即系统在某 个时刻所有线程的运行状态,包括每一个线程的调用堆栈,锁的持有情况等信息。
每一种Java虚拟机(SUN JVM、 IBM JVM、 JRokit、 GNU JVM等等)都提供了线程转储(thread dump)的后门, 通过这个后门可以将那个时刻的线程堆栈打印出来。
虽然各种Java虚拟机在线程堆栈的打印输出格式上有一些不同, 但是线程堆栈的信息都包含:

  1. 线程的名字,ID,线程的数量等。
  2. 线程的运行状态,锁的状态(锁被哪个线程持有,哪个线程再等待锁等)。
  3. 调用堆栈(即函数的调用层次关系)。调用堆栈包含完整的类名,所执行的方法,源代码的行数。

适合解决的问题

系统无缘无故CPU过高。
• 系统挂起, 无响应。
• 系统运行越来越慢。
• 性能瓶颈(如无法充分利用CPU等)
• 线程死锁、 死循环, 饿死等。
• 由于线程数量太多导致系统失败(如无法创建线程等)。

输出堆栈情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MyTest {
final Object obj1 = new Object();
final Object obj2 = new Object();

public void fun1() {
synchronized (obj1) {
fun2();
}
}

public void fun2() {
synchronized (obj2) {
while (true) {
//为了演示需要,该函数永不退出
System.out.print("");
}
}
}

public static void main(String[] args) {
MyTest aa = new MyTest();
aa.fun1();
}
}

启动上述程序后进程不会终止,然后通过如下命令给该进程发一个 quit 信号

1
2
$ jps # to find pid of the java process
$ kill -3 pid

得到输出中包含了 main 线程(java 用户线程)以及其他几个虚拟机自建的线程,我们只关心 main 线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"main" #1 prio=5 os_prio=31 tid=0x000000011c80e800 nid=0x2903 runnable [0x000000016fe12000]
java.lang.Thread.State: RUNNABLE
at MyTest.fun2(MyTest.java:15)
- locked <0x000000076ab66aa0> (a java.lang.Object)
at MyTest.fun1(MyTest.java:8)
- locked <0x000000076ab66a90> (a java.lang.Object)
at MyTest.main(MyTest.java:22)

"main" #1 prio=5 os_prio=31 tid=0x000000011c80e800 nid=0x2903 runnable [0x000000016fe12000]
| | | | | |
| | | | | +--线程占用内存地址
| | | | +-----------线程的状态
| | | +----线程对应的JVM本地线程id号
| | +-------------------线程id
| +--------------------------线程优先级
+-------------------------------线程名称

locked <0x000000076ab66aa0> 中的 0x000000076ab66aa 代表锁id,同一个锁id相同

pstack pid

1
2
3
4
5
6
7
8
9
10
Thread 1 (Thread 4160560000 (LWP 10499)):
#0 0xf28fc863 in ?? ()
#1 0x00000000 in ?? ()
#0 0xf28fc863 in ?? ()

Thread 1 (Thread 4160560000 (LWP 10499)):
| | |
| | +----本地线程id(另一种表示,LWP-light weight process)
| +-------------------本地线程id
+------------------------------线程名称

“runnable”表示当前线程处于运行状态。 这个runnable状态是从虚拟机的角度来看的,表示这个线程正在运行。
但是处于Runnable状态的线程不一定真地消耗CPU. 处于Runnable的线程 只能说明该线程没有阻塞在java的wait或者sleep方法上,同时也没等待在锁上面。
但是如果该线程调用了本地方法,而本地方法处于等待状态, 这个时候虚拟机是不知道本地代码中发生了什么,此时尽管当前线程实际上也是阻塞的状态,但实际上显示出来的还是runnable状态 这种情况下是不消耗CPU的。

在以下条件中该类不会拥 有() 方法:
• 该类既没有声明任何类变量, 也没有静态初始化语句;
• 该类声明了类变量, 但没有明确使用类变量初始化语句或静态初始化语句初始化;
• 该类仅包含静态final 变量的类变量初始化语句, 并且类变量初始化语句是编译时常量表达式

Java 编译器在编译每个类时都会为该类至少生成一个实例初 始化方法–即"<init>()"方法。
此方法与源代码中的每个构造方法相对应, 如果类没有明确地声明任何构造方法, 编译器则为该类生成一个默认的无参构造方法,
这个默认的构造器仅仅调 用父类的无参构造器, 与此同时也会生成一个与默认构造方法对应的"<init>()" 方法.
通常来说,<init>() 方法内包括的代码内容大概为: 调用另一个 <init>()方法; 对实例变量初始化; 与其对应的构造方法内的代码。

  • 如果构造方法是明确地从调用同一个类中的另一个构造方法 开始, 那它对应的() 方法体内包括的内容为:
    • 一个对本类的 <init>() 方法的调用;
    • 对应用构造方法内的所有字节码。
  • 如果构造方法不是通过调用自身类的其它构造方法开始,并且该对象不是Object 对象,那<init>() 法内则包括的内容为:
    • 一个对父类 <init>() 方法的调用;
    • 对实例变量初始化方法的字节码;
    • 最后是对应构造子的方法体字节码。

如果这个类是Object, 那么它的() 方法则不包括对父类() 方法的调用

CATALOG
  1. 1. 参数附录
  2. 2. 简介
  3. 3. 适合解决的问题
  4. 4. 输出堆栈情况