一:介绍
- 什么是JVM
定义:java virtual meachine -java运行时环境(java二进制字节码的运行环境)。 - 好处:
一次编写到处运行
自动内存管理,垃圾回收
数组下标越界检查
多态
java虚拟机:
java的内存结构包括:
- 程序计数器
- 虚拟机栈
- 本地方法栈
- 堆
- 方法区
1.1 程序计数器
- java代码在执行的过程:首先被编译成二进制字节码(jvm指令),然后通过解释器生成为机器码,最后才会被CPU执行。
- 而解释器在执行每一条字节码指令时,需要程序计数器来指定需要执行的指令。此时程序计数器中存储的是jvm下一个执行的地址
- 正是因为能编辑为机器码,jvm才有一次编辑,多平台使用。因为无论linux和windows系统,都会执行机器码
特点:
- 线程私有
- 不会出现内存泄漏
1.2 栈
1.2.1栈的定义
定义:
- 每个线程运行时所需要的内存,称为虚拟机栈
- 每个栈由多个栈帧组成,对应着每次方法调用时所占用的内存
- 每个线程只能有一个活动栈帧(正在执行的方法),对应着当前正在执行的那个方法
- 特点:先进后出
一个线程需要一个栈;一个栈帧对应一个方法的调用;
栈和栈帧的关系:线程执行方法的时候,会调用方法,会将栈栈放入栈内,当方法执行完后,会将栈帧释放掉
问题解析:
1:垃圾回收是否涉及栈内存
不涉及,方法执行完后,对应的栈帧就会被出栈,被释放掉,不涉及垃圾回收
2:栈内存分配越大越好吗?
不是:物理内存大小是一定的,当栈内存大时,线程数就会少。
3:方法内的局部变量是否线程安全?
- 如果方法内局部变量没有逃离方法的作用访问,是线程安全的
- 如果是局部变量引用了对象,并逃离方法的作用方法,需要考虑线程安全
查看线程是否安全:看这个变量对多个线程是共享的,还是私有的
public class Demo{
static void hello(){
int x=0;
for (int i=0;i<100;i++){
x++;
}
System.out.println(x);
}
}
此时线程安全
此时局部变量是线程不安全的
public class Demo{
static void hello(){
static int x=0;
for (int i=0;i<100;i++){
x++;
}
System.out.println(x);
}
}
1.2.2 栈内存溢出
STACKOVERFLOWERROE
什么情况会导致内存溢出
- 栈帧多时,一直有栈帧进栈;当递归次数多时
- 栈帧过大导致内存溢出,
1.2.3 线程运行诊断
-
案例一:cpu占用过多
定位- 用top定位哪个线程对cpu占用过高
- ps -H pid,tid,%cpu | grep 进程id,(用ps命令进一步定位那个线程引起的cpu占用过高)
- jstack 进程id
- 可以根据线程id,找到问题的线程,进一步定位到出现问题的代码
-
案例二:一段程序,运行好长时间,没有等到返回的结果