深入理解JVM(一)-------JVM运行机制

JVM运行机制介绍

  • JVM启动流程
  • JVM基本结构
  • JVM内存模型
  • 编译和解释运行的概念

JVM启动流程

我们先看大概的流程图:
Alt text

配置JVM装载环境

当我们执行java -jar xxxx.jar 的时候,Java代码执行时需要JVM环境,JVM环境的创建包括:JVM.dll文件的查找和装载。

虚拟机参数解析

设置线程栈大小

执行main方法

JVM基本结构

Alt text

PC寄存器

  • 每个线程拥有一个PC寄存器
  • 在线程创建时创建
  • 指向下一条指令的地址
  • 执行本地方式时,PC的值为undefined

方法区

  • 保存装载的类信息:类型的常量池、字段和方法信息、方法字节码
  • 通常和永久区(Perm)关联在一起
    注:移除永久代的工作从JDK1.7就开始了,在JDK1.7中,存储在永久代的部分数据已经转移到了Java堆或者是Native Heap,JDK1.8中,HotSpot已经没有 “PermGen space” 这个区间了,取而代之的是一个叫做Metaspace(元空间)的东西。

Java堆

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

Java栈

  • 线程私有
  • 栈由一系列帧组成(因此Java栈也叫做帧栈)
  • 帧保存一个方法的局部变量、操作数栈、常量池指针
  • 每一个方法调用创建一个帧,并压栈

Java栈上分配

  • 小对象(一般几十个字节)在没有逃逸的情况下,可以直接分配在栈上
  • 直接分配在栈上,可以自动回收,减轻GC压力
  • 大对象或者逃逸对象无法栈上分配

如何让函数递归调用层次更深?
可以从以下两个方面解决:第一,增大栈空间;第二,减少局部变量表,少用double、long,减少参数个数,局部变量在使用的时候,注意作用域。在作用域开外的,局部变量是可以被重用的,以此减少局部变量表的大小。

JVM内存模型

Alt text

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

可见性

  • 一个线程修改了变量,其他线程可以立即知道

保证可见性的方法

  • volatile
  • synchronized(unlock之前,写变量值回主存)
  • final(一旦初始化完成,其他线程就可见)

有序性

  • 在本线程内,操作都是有序的
  • 在线程外观察,操作都是无序的(指令重排或者主内存同步延时)