定义: Java Virtual Machine - java程序的运行环境 (java二进制字节码的运行环境)
好处:
- 一次编写,到处运行
- 自动内存管理,垃圾回收功能
- 数据下标越界检查
- 多态
比较:
JRE: Java Runtime Enviroment()
常见的JVM:
学习路线:
内存结构
程序计数器
- Program Counter Register 程序计数器(寄存器)
作用:
用于保存下一条JVM指令的执行地址地址
特点:
1.是线程私有的:
CPU会为每个线程分配时间片,当当前线程的时间片使用完以后,CPU就会去执行另一个线程中的代码
程序计数器是每个线程所私有的,当另一个线程的时间片用完,又返回来执行当前线程的代码时,通过程序计数器可以知道应该执行哪一句指令
2.不会存在内存溢出
虚拟机栈
定义:
- 每个线程运行时所需要的内存,称为虚拟机栈
- 每个栈由多个栈帧组成,对应着每次方法调用时所占用的内存
- 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
问题辨析:
1.垃圾回收是否涉及栈内存?
- 不涉及,因为虚拟机栈是有一个个栈帧组成的,在方法执行完毕后,对应的栈帧就会被弹出栈。所以无需通过垃圾回收机制去回收内存。
2.栈内存的分配越大越好吗?
- 不是,因为物理内存是一定的,栈内存越大,可以支持更多的递归调用,但是可执行的线程数就会越来越少
3.方法内的局部变量是否是线程安全的?
- 如果方法内局部变量没有逃离方法的作用范围,则是线程安全的
- 如果局部变量引用了对象,并逃离了方法的作用范围,则需要考虑线程安全问题
栈内存溢出
Java.lang.stackOverflowError 栈内存溢出
- 栈帧过多导致栈内存溢出(无限递归)
- 栈帧过大导致内存溢出
线程运行诊断
CPU占用过高
- Linux环境下运行某些程序的时候,可能导致CPU的占用过高,这是需要定位占用CPU过高的线程
- ps H -en pid, tid, %cpu | grep 刚才通过top查到的进程号 通过ps命令进一步查看是哪个线程占用CPU过高
- jstack 进程id 通过查看进程中的线程的nid,刚才通过ps命令看到的tid来对比定位,注意jstack查找出的线程id是16禁止的,需要转换
迟迟得不到结果
- 可能发生了死锁
本地方法栈
一些带有native关键字的方法就是需要JAVA去调用本地的C或者C++方法,因为JAVA有时候没法直接和操作系统底层交互,所以需要用到本地方法
堆
定义
通过new关键字,创建的对象都会使用堆内存
特点
- 他是线程共享的,堆中对象都需要考虑线程安全的问题
- 有垃圾回收机制
堆内存溢出
java.lang.OutofMemoryError :java heap space
堆内存诊断
1.jps工具
- 查看当前系统中有哪些java进程
2.jmap工具
- 查看堆内存占用情况
3.jconsole工具
- 图形界面的,多功能的监测工具,可以连续监测
4.jvirsalvm
方法区
定义
方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。
方法区内存溢出
- 1.8以前会导致永久代内存溢出
- 1.8之后会导致元空间内存溢出
通过反编译来查看类的信息
获得对应类的.class文件
在JDK对应的bin目录下运行cmd,也可以在IDEA控制台输入
输入 javac 对应类的绝对路径
F:\JAVA\JDK8.0\bin>javac F:\Thread_study\src\com\nyima\JVM\day01\Main.javaCopy
输入完成后,对应的目录下就会出现类的.class文件
在控制台输入 javap -v 类的绝对路径
javap -v F:\Thread_study\src\com\nyima\JVM\day01\Main.classCopy
然后能在控制台看到反编译以后类的信息了
运行时常量池
- 常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
- 运行时常量池,常量池是*.class文件中的,当该类被加载,他的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址