JVM基本结构、内存模型

JVM基本结构图

Markdown

  • PC寄存器
1
2
3
1、每个线程拥有一个PC寄存器
2、在线程创建时创建
3、指向下一条指令的地址

方法区

1
2
3
4
5
6
7
1、保存装载的类信息
- 类型的常量池
- 字段、方法信息
- 方法字节码
2、通常和永久区绑定在一起
```
### Java堆

1、所有线程共享Java堆
2、分新生代、老年代
3、新生代分s0 s1区
4、Java堆和程序数据密切相关

1
2
3
> 在绝大多数情况下,对象首先分配在eden区,在一次新生代回收之后,如果对象还存活,则进入s0或者s1,每经过一次新生代回收,对象如果存活,它的年龄就会加1。当对象的年龄达到一定条件后,就会被认为是老年对象,从而进入老年代。

> GC分代收集

package com.jvm;
public class SimpleHeap {
  private int id;
  public SimpleHeap(int id){
    this.id = id;
  }
  public void show(){
    System.out.println(“My id is “+id);
  }

  public static void main(String[] args) {
    SimpleHeap s1 = new SimpleHeap(1);
    SimpleHeap s2 = new SimpleHeap(2);
    s1.show();
    s2.show();
  }
}

1
2
3
![Markdown](http://i2.bvimg.com/634857/f410cf1a4a78d225.png)

### Java栈

1、Java栈和线程执行相关
2、线程私有
3、先进后出
4、栈由一系列帧组成
5、静态方法和非静态方法 第一个局部变量的槽位不同,非静态第一个槽位是this的引用

1
2
3
4
5
6
7
8
9
10
- 局部变量表

> 局部变量表是栈帧的重要组成部分之一。它用于保存函数的参数以及局部变量,局部变量表中的变量只在当前函数调用中有效,当函数调用结束,随着函数栈帧的弹出销毁,局部变量表也会随之销毁。

> 由于局部变量表在栈帧之中,因此,如果函数的参数和局部变量很多,会使得局部变量表膨胀,从而每一次函数调用就会占用更多的栈空间,最终导致函数的嵌套调用次数减少。

- 操作数栈


- Java栈 栈上分配

1、小对象、栈上分配
2、大对象或者逃逸对象无法栈上分配
3、栈上分配,使用完毕,可以自动回收,减轻GC的压力

1
### 内存模型

1、每一个线程有一个工作内存和主内存独立
2、工作内存存放主存中的变量的值和拷贝

1
### 可见性

1、volatile关键字修饰
2、synchronize
3、final(一旦初始化完成,其他线程可见)

1
2

### 有序性

1、一个线程内会有指令重排
2、synchronize修饰了函数,可以保证指一个线程内令重排后,其他线程读取到的值是最新的

1
2

### 指令重排

1、程序顺序规则:首先保存程序顺序的前提下会出现指令重排
a=4;b= a+1; 这种情况不会指令重排
一个线程内保证语义的串行性
2、volatile规则:volatile变量的写,先发生于读
3、锁规则:解锁必然先发生在随后的加锁(lock)💰
`