什么是JVM
定义
Jvav Virtual Machine - java程序的运行环境(Java二进制字节码的运行环境)
好处
- 一次编写, 到处运行
- 自动内存管理, 垃圾回收功能
- 数组下标越界检查
- 多态
比较
硬件<>系统(Win,Linux)<>JVM–>JRE(JVM+基础类库)–>JDK(JRE+编译工具)
Java虚拟机家族
- 虚拟机始祖: Sun Classic/Exact VM
- 武林盟主: HotSpot VM
- 小家碧玉: Mobile/Embedded VM
- 天下第二: BEA JRockit/IBM J9 VM
- 软硬结合: BEA Liquid VM/Azul VM
- 挑战者: Apache Harmony VM/Google Android Dalvik Vm
JVM的内存结构
1. 程序计数器
1.1定义
程序计数器(Program Counter Register)是一块较小的内存空间, 它可以看作是当前线程所执行的字节码的行号指示器.
1.2 作用
- 记住下一条JVM指令的执行地址
- 线程私有
- 唯一一个在<<Java虚拟机规范>>规范中没有任何OutOfMemoryError情况的内存
2. Java虚拟机栈
2.1 定义
Java虚拟机栈(Java Virtual Machine Stack)线程私有, 它的生命周期与线程相同.
- 每个线程运行时所需要的内存, 称为虚拟机栈
- 每个栈由多个栈帧(Stack Frame)组成, 对应着每个方法调用是所占用的内存
- 每个线程只能有一个活动栈帧, 对应着当前正在执行的那个方法
问题辨析
-
垃圾回收是否涉及栈内存?
垃圾回收机制不会回收栈的内存, 回收的是堆内存无用数据
-
栈内存分配越大越好吗?
不是,内存越大反而线程会减少
-
方法内存的局部变量是否线程安全?
-
如果方法内部局部变量没有逃离方法的作用访问, 它是线程安全的 如果是局部变量引用了对象, 并逃离方法的作用范围, 需要考虑线程安全
2.2 栈内存溢出
- 栈帧过多导致栈内存溢出(StackOverflowError 例如: 递归)
- 栈帧过大导致栈内存溢出
2.3 线程运行诊断
案例1: cpu占用过多
定位
-
用top定位那个进程对cpu的占用过多
-
ps H -eo pid,tif,%cpu|grep进程id(用ps命令进一步定位那个线程引起的cpu占用过高)
-
jstack进程id
- 可以根据线程id找到有问题的线程, 进一步定位到问题代码的源码号
案例2: 线程运行很长时间没有结果
发生线程死锁