JVM 简介、程序计数器、虚拟机栈
JVM是什么?
定义:Java Virtual Machine - java程序的运行环境 (java 二进制字节码的运行环境)
Java的优点(JVM)
- 一次编写,到处运行
- 自动内存管理,垃圾回收功能
- 数组下标越界越界检查
- 多态
JVM JDK JRE 的关系
Program Counter Register程序计数器(寄存器)
在java代码进行编译执行的时候,先将java代码转换成二进制的编码,这个地方的二进制编码就是jvm指令,jvm的指令会给到解释器,而在这里程序计数器就会记住吓一跳jvm指令的地址。这就是程序计数器。
程序计数器的特点
- 是线程私有的
- 不会存在内存溢出
Java Virtual Machine Stack 虚拟机栈
定义 :每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
使用代码进行测试,代码如下:一段简单的java代码,在设置断点,进行debug,每执行一条语句,这个方法会占用内存,也就是会被放进这个栈当中,当方法执行完成之后再进行出栈操作。
问题辨析
- 垃圾回收是否涉及栈内存?
答:栈的内存不需要进行回收。 - 栈内存分配越大越好吗?
答:不是,内存分配的越大,线程的数目会变少,采取默认大小即可。 - 方法内的局部变量是否线程安全?
答:如果方法内局部变量没有逃离方法的作用访问,它是线程安全的。如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全。
在第三个问题当中,使用以下代码进行测试:其中只有第一个方法时线程安全的。方法二由于有值进行传递进来,不能确保线程是安全的。第三个方法由于有返回值所以线程也是不安全的。
public class thread_security {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append(4);
sb.append(5);
sb.append(6);
new Thread(() -> {
m2(sb);
}).start();
}
public static void m1() {
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.append(1);
sb.append(2);
sb.append(3);
System.out.println(sb.toString());
}
public static StringBuilder m3() {
StringBuilder sb = new StringBuilder();
sb.append(1);
sb.append(2);
sb.append(3);
return sb;
}
}
栈内存溢出
容易导致栈内存溢出出现的情况
- 栈帧过多导致栈内存溢出
- 栈帧过大导致栈内存溢出
通过以下代码演示栈内存溢出这种情况,代码当中在一致调用method1这个方法,每次调用后栈帧会加一,但是没有设置出栈,最后肯定会导致栈内存溢出,出现报错,在这里设置一个静态变量count进行记录,调用多少次之后才会溢出。
public class stack_overflow {
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();
}
}
运行代码出现报错:java.lang.StackOverflowError
栈内存溢出。大概在2w多次将会溢出
在这里我们可以设置栈的大小,查看调用次数和大小是否有关,在eclipse当中,右键单击代码编辑区,选择Run As 下的run configurations,如下图:
再次运行代码,可以发现,运行次数很显然变少了,可以得出,栈的内存大小和溢出有关
线程运行诊断
案例:一个应用占据的cpu过高,
- 在linux系統下,使用top命令进行定位,定位到哪个进程对cpu占用过高。使用
ps H -eo pid,tid,%cpu | grep 进程id
(用ps命令进一步定位是哪个线程引起的cpu占用过高)。使用jstack 进程id
可以根据线程id 找到有问题的线程,进一步定位到问题代码的源码行号
还没有评论,来说两句吧...