JVM详解(一基本概念、运行机制)

JVM详解(一基本概念、运行机制)

JVM基本概念

  • JVM
    Java Virtual Machine的简称,意为Java虚拟机。
    使用最为广泛的JVM为HotSpot,HotSpot 为Longview Technologies开发 被SUN收购。
    JVM主要定义二进制class文件和JVM指令集等。
  • 虚拟机
    指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。如VMWare、JVM。
    VMWare是使用软件模拟物理CPU的指令集。
    JVM使用软件模拟Java 字节码的指令集。

JVM运行机制

  • JVM启动机制
    这里写图片描述
  • JVM基本结构
    这里写图片描述
    1. PC寄存器
      • 每个线程拥有一个PC寄存器
      • 在线程创建时创建
      • 指向下一条指令的地址
      • 执行本地方法时,PC的值为undefined。
    2. 方法区
      保存装载的类信息。
      • 常量池
      • 字段,方法信息
      • 方法字节码
      • 通常和永久区(Perm)关联
        (JDK6时,String等常量信息置于方法区;JDK7时,已经移动到了堆。)

      • 和程序开发密切相关
      • 应用系统对象都保存在Java堆中
      • 所有线程共享Java堆
      • 对分代GC来说,堆也是分代的
      • GC的主要工作区间
        这里写图片描述

      • 线程私有
      • 栈由一系列帧组成(因此Java栈也叫做帧栈)
      • 帧保存一个方法的局部变量、操作数栈、常量池指针
        这里写图片描述
        这里写图片描述
      • 每一次方法调用创建一个帧,并压栈
        这里写图片描述
      • 栈上分配
        1)小对象(一般几十个bytes),在没有逃逸的情况下,可以直接分配在栈上
        2) 直接分配在栈上,可以自动回收,减轻GC压力
        3) 大对象或者逃逸对象无法栈上分配
        这里写图片描述
    3. 栈、堆、方法区交互
      这里写图片描述
// 运行时, jvm 把appmain的信息都放入方法区
public class AppMain {
    public static void main(String[] args) {
        // test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面
        Sample test1 = new Sample(" 测试1 ");
        test1.printName();
        Sample test2 = new Sample(" 测试2 ");
        test2.printName();
    }
}

//运行时, jvm 把appmain的信息都放入方法区 
public  class Sample{
    private String name;
    //new Sample实例后,name引用放入栈区里,name对象放入堆里
    public Sample(String name){
        this.name = name;
    }
    //print方法本身放入 方法区里。
    public void printName() {
        System.out.println(name);
    }
}

线程内存

  1. 内存模型
    • 每一个线程有一个工作内存和主存独立
    • 工作内存存放主存中变量的值的拷贝
      这里写图片描述
      当数据从主内存复制到工作线程存储时,必须出现两个动作:第一,由主内存执行的读(read)操作;第二,由工作内存执行的相应的load操作;当数据从工作内存拷贝到主内存时,也出现两个操作:第一个,由工作内存执行的存储(store)操作;第二,由主内存执行的相应的写(write)操作。
      每一个操作都是原子的,即执行期间不会被中断。
      对于普通变量,一个线程中更新的值,不能马上反应在其他变量中。
      这里写图片描述
public class VolatileStopThread extends Thread {
    private volatile boolean stop = false;

    public void stopMe() {
        stop = true;
    }

    public void run() {
        int i = 0;
        while (!stop) {
            i++;
        }
        System.out.println("Stop thread");
    }

    public static void main(String args[]) throws InterruptedException {
        VolatileStopThread t = new VolatileStopThread();
        t.start();
        Thread.sleep(1000);
        t.stopMe();
        Thread.sleep(1000);
    }
}

以上方法,没有volatile,运行无法停止。


如果需要在其他线程中立即可见,需要使用 volatile 关键字。
volatile不能代替锁。
一般认为volatile 比锁性能好(不绝对)。
选择使用volatile的条件是:语义是否满足应用。
7. 可见性
一个线程修改了变量,其他线程可以立即知道。
保证可见性的方法:
1) volatile
2) synchronized(unlock之前,写变量值回主存)
3)final(一旦初始化完成,其他线程就可见)
8. 有序性
1)在本线程内,操作都是有序的。
2)线程外观察,操作都是无序的。(指令重排或主内存同步延时)
9. 指令重排
线程内串行语义

- 写后读   a = 1;b = a;    写一个变量之后,再读这个位置。
- 写后写   a = 1;a = 2;    写一个变量之后,再写这个变量。
- 读后写   a = b;b = 1;    读一个变量之后,再写这个变量。

以上语句不可重排
编译器不考虑多线程间的语义
可重排: a=1;b=2;

class OrderExample {
    int a = 0;
    boolean flag = false;

    public void writer() {
        a = 1;
        flag = true;
    }

public void reader() {
    if (flag) {                
        int i =  a +1;      
        ……
        }
    }
}

线程A首先执行writer()方法
线程B线程接着执行reader()方法
线程B在int i=a+1 是不一定能看到a已经被赋值为1
因为在writer中,两句话顺序可能打乱
线程A:flag=true,a=1
线程B:flag=true(此时a=0)

class OrderExample {
    int a = 0;
    boolean flag = false;

    public synchronized void writer() {
        a = 1;
        flag = true;
    }

public synchronized void reader() {
    if (flag) {                
        int i =  a +1;      
        ……
        }
    }
}

同步后,即使做了writer重排,因为互斥的缘故,reader 线程看writer线程也是顺序执行的。
线程A:flag=true,a=1
线程A:flag=true,a=1


  • 指令重排的基本原则
    程序顺序原则:一个线程内保证语义的串行性
    volatile规则:volatile变量的写,先发生于读
    锁规则:解锁(unlock)必然发生在随后的加锁(lock)前
    传递性:A先于B,B先于C 那么A必然先于C
    线程的start方法先于它的每一个动作
    线程的所有操作先于线程的终结(Thread.join())
    线程的中断(interrupt())先于被中断线程的代码
    对象的构造函数执行结束先于finalize()方法
  • 解释运行
    解释执行以解释方式运行字节码
    解释执行的意思是:读一句执行一句
  • 编译运行(JIT)
    将字节码编译成机器码
    直接执行机器码
    运行时编译
    编译后性能有数量级的提升
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值