一、定义
Java Virtual Machine --java的运行环境(java二进制字节码的运行环境)
JVM提供的功能:
- 一次编写,到处运行
- 自动内存管理,垃圾回收功能
- 数组下标越界检查
- 多态
比较(包含关系)
JVM
JRE:JVM+基础类库 Java RuntimeEnvironment
JDK:JVM+基础类库+编译工具
开发JavaSE: JDK+IDE
开发JavaEE:JDK+应用服务器+IDE
jvm是一套规范eg :HotSpot,Oracle JDK
二、JVM内存结构
java源代码-> 二进制字节码(jvm指令)->解释器->解释为机器码->CPU
1. 程序计数器
作用:记住下一条jvm指令的执行地址
特点:
- 是线程私有的(每个线程有自己的程序计数器)
- 不会存在内存溢出
2. 虚拟机栈
定义
栈-线程运行需要的内存空间
栈帧组成
一个栈帧对应一次方法的调用 每个方法运行时需要的内存
包含的信息有:参数,局部变量,返回地址等
当方法执行完,就把这个栈帧弹出
总结
- 每个线程运行时需要的内存,称为虚拟机栈
- 每个栈由多个栈帧组成,对应着每次方法调用时所占用的内存
- 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
问题
- 垃圾回收是否涉及栈内存? no 不需要垃圾回收。GC回收堆内存中的对象
- 划分更多栈内存? 不会提升效率
- 方法内的局部变量是否线程安全? (线程中变量有无共享?)
每个线程各有一个栈,线程中的每个方法各有一个栈帧,调用时放到该线程的栈里。 共享的变量才要考虑线程安全问题
栈内存溢出
- 递归没有合理的结束条件(栈帧过多导致栈溢出)
- 栈帧过大导致栈溢出
线程运行诊断
- CPU占用过多
- 死锁
3. 本地方法栈 Native Method Stacks
不是java代码编写的接口。其他语言的本地方法接口需要使用本地方法栈
native
作用:给本地方法的运行提供内存空间
4. 堆
通过new关键字,创建对象都会使用堆内存
特点:
- 它是有线程共享的,堆中对象都需要考虑线程安全的问题
- 有垃圾回收机制
堆内存溢出
OutOfMemoryError: Java heap space
堆内存诊断:
- jps工具 查看进程
jps
- jmap 查看堆内存占用情况
jmap -heap 进程id
- jconsole 图形界面 jdk自带
案例:垃圾回收后,内存占用仍然很高
jvisualvm
点击[堆dump] 可以截取快照
5. 方法区
线程内共享的区域,存与类相关的信息
方法区在虚拟机启动时被创建,逻辑上是堆的组成部分方法区也会导致内存溢出。
1.8以前导致永久代内存溢出
1.8以后会导致元空间内存溢出
元空间内存溢出
场景: Spring MyBatis
运行时常量池
二进制字节码组成:类基本信息,常量池,类方法定义-包含了虚拟机指令
.class javap -v Helloworld.class
常量池就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
运行时常量池,常量池是*.class文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址(内存中的地址)。