一、基本
1. 基本概念
- 红色部分:会随着虚拟机的启动而创建,随着虚拟机的退出而销毁
- 灰色部分:与线程一一对应,随着线程的启动和结束,随之产生而结束
- 一个Runtime, 对应一个JVM虚拟机
2. 线程
1. 线程是一个程序里的运行单元, JVM允许一个一个应用有多个线程并行执行
2. 每个线程都与操作系统的本地线程直接映射
2.1 当一个java线程准备好后,此时一个操作系统的本地线程也会创建
2.2 java线程执行终止后,本地线程也会回收
3. 操作系统负责将线程的安排调度到任何一个可用的cpu上
一旦本地线程初始化成功,就会调用java线程中的run()
二、程序计数器
1. 概念
- PC寄存器, PC Register, Program Counter Register, 指令计数器
- 线程的代码指令:通过程序计数器来进行保存和再次获取,就是用来线程切换
- 一个线程中会包含一个程序计数器,记录代码指令执行行数,属于线程私有
- 存储空间比较小,几乎可以忽略不计,也是运行速度最快的
- 不存在OOM
任何时候一个线程只有一个方法可以执行(当前方法)
存储当前线程正在执行的java方法的jvm指令地址,如果执行native方法,则是undefined
三、栈
栈: 1. 是运行时的单位
2.解决程序的运行问题,程序如何执行,如何处理数据
堆: 1. 存储的单位
2. 堆解决的问题是数据存储的问题, 存在哪儿?如何存?
1. 基本
1.1 基本介绍
JAVA虚拟机栈(JAVA栈)
每个线程在创建的时候,都会创建一个虚拟机栈,
栈内部保存一个个的栈帧(Stack Frame), 对应着一次次的java方法调用
是线程私有的
- 生命周期和线程一致
- 主管java程序的运行,保存方法的局部变量,部分结果,参与方法的调用和返回
1. 快速有效的分配存储方式,访问速度仅次于程序计数器
2. JVM 对java 栈的操作: 方法入栈和出栈
3. 栈不存在垃圾回收
4. 可能出现 OOM
1.2 大小设置
Java栈的大小是 动态 或者 固定可变的
1. 固定大小: 每个线程的栈内存在线程创建的时候独立选定, 默认的!
如果线程请求的栈容量超过了最大容量, 则 StackOverflowError
2. 动态分配: 可以动态分配
如果在尝试扩展的时候无法申请到足够的内存,或者创建新线程时没有足够的内存
则OutOfMemoryError
package com.nike.erick.d05;
public class Demo02 {
public static void main(String[] args) {
main(args);
}
}
- Xss256k: 设置栈内存大小为256k
1.3 存储单位
- 每个线程都有自己的栈,栈中的数据以栈帧( Stack Frame)的格式存在
- 一个线程上,正在执行的每个方法都各自对应一个栈帧
- 栈帧是一个内存模块,是一个数据集,维系着方法执行过程中的各种数据信息
- FILO原则
- 一条活动线程中,一个时间点上,只会有一个活动的栈帧
- Current Frame, Current Method, Current Class
- 执行引擎运行的所有字节码指令, 只针对当前栈帧进行创建
- 如果在一个方法中调用了其他方法,对应新的栈帧就会被创建出来,成为新的当前帧
1. 不同线程中包含的栈帧是不允许存在相互引用的, 不能在一个栈帧中引用另外一个线程的栈帧
但是可以共享主存中的数据
2. 如果当前方法调用了其他方法,方法返回后,当前栈帧会传递回此方法的执行结果给前一个栈帧
虚拟机回丢弃当前栈帧,使得前一个栈帧重新成为当前栈帧
3. 正常方法返回(return指令) 抛出异常, 都会导致 栈帧 被弹出
2. 栈帧结构
2.1 局部变量表
1. 定义一个 数字数组, 存储。
方法参数, 定义在方法体内的局部变量(基本数据类型, 对象引用),returnAddress
2. 局部变量表是建立在线程的栈上, 是线程私有的,不存在数据安全问题
3 . 局部变量表的容量大小是在编译期确定下来的,并保存在方法的 Code属性的 maximum local variables
在方法运行期间不会改变局部变量表的大小
2.1.1 代码解析
- javap -v Demo03.class: 解析class文件
package com.nike.erick.d05;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Demo03 {
public static void main(String[] args) {
}
public Set<String> method01(String address){
List<String> erickList = new ArrayList<>();
double phone = 1234567654;
int age = 100;
return new HashSet<>();
}
public Set<String> method02(String address){
double phone = 1234567654;
int a = 1;
{
int b = a+1;
b = 0;
}
int age = 100;
return new HashSet<>();
}
}
{
public com.nike.erick.d05.Demo03();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial
4: return
LineNumberTable:
line 8: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/nike/erick/d05/Demo03;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 11: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 args [Ljava/lang/String;
public java.util.Set<java.lang.String> method01(java.lang.String);
descriptor: (Ljava/lang/String;)Ljava/util/Set;
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=6, args_size=2
0: new
3: dup
4: invokespecial
7: astore_2
8: ldc2_w
11: dstore_3
12: bipush 100
14: istore 5
16: new
19: dup
20: invokespecial
23: areturn
LineNumberTable:
line 14: 0
line 15: 8
line 16: 12
line 17: 16
LocalVariableTable:
Start Length Slot Name Signature
0 24 0 this Lcom/nike/erick/d05/Demo03;
0 24 1 address Ljava/lang/String;
8 16 2 erickList Ljava/util/List;
12 12 3 phone D
16 8 5 age I
LocalVariableTypeTable:
Start Length Slot Name Signature
8 16 2 erickList Ljava/util/List<Ljava/lang/String;>;
Signature:
public java.util.Set<java.lang.String> method02(java.lang.String);
descriptor: (Ljava/lang/String;)Ljava/util/Set;
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=6, args_size=2
0: ldc2_w
3: dstore_2
4: iconst_1
5: istore 4
7: iload 4
9: iconst_1
10: iadd
11: istore 5
13: iconst_0
14: istore 5
16: bipush 100
18: istore 5
20: new
23: dup
24: invokespecial
27: areturn
LineNumberTable:
line 21: 0
line 23: 4
line 25: 7
line 26: 13
line 28: 16
line 29: 20
LocalVariableTable:
Start Length Slot Name Signature
13 3 5 b I
0 28 0 this Lcom/nike/erick/d05/Demo03;
0 28 1 address Ljava/lang/String;
4 24 2 phone D
7 21 4 a I
20 8 5 age I
Signature:
}
SourceFile: "Demo03.java"
2.1.2 Slot槽
局部变量表中, 最基本的存储单元是Slot 槽
1. slot中可以保存8中基本数据类型,引用类型的引用, returnAdrress类型的变量
2. 32以内的类型只占用一个slot(基本及引用类型), 64位的类型占用两个slot
2.1 byte,short,char在存储前转换为int,boolean转换为int
2.2 long和double则占据两slot
3. 实例方法被调用时候,方法参数和局部变量会按照顺序复制到变量表中每个slot上
4. 当前栈是实例方法创建, slot0索引位置存放this对象引用(解释了static和普通方法区别)
5. slot插槽可以重复利用(销毁的slot可以被后面的复用)
|