JVM第一话 -- JVM入门详解以及运行时数据区分析

1.JVM是什么

JVM(Java Virtual Machine) 是Jvm虚拟机的一种规范。

C:\Users\pc>java -version
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)

当安装了JDK以后,可以看到默认是已安装HotSpot虚拟机的,Java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,所以Java语言是跨平台语言。

这也就体现出了Java语言的特点: 一处编译,多处执行,跨平台,安全性(1.摒弃指针 2、GC垃圾回收机制:(自动释放回收长时间不使用对象的内存))

结构:JDK & JRE & JVM三者结构图
结构关系图

  • jvm分布结构图
    输入class文件到虚拟机,虚拟机输出不同平台的CPU指令。存储器、控制器、运算器 为JVM运行时数据区
    在这里插入图片描述

2.一个java文件的编译运行过程

工具:javac编译、javap反编译

Java源文件 -> Javac编译成class文件 -> JVM虚拟机运行Class文件实则为转成对应操作系统的机器码 -> 各大操作系统

2.1 javac

Javac将源文件转成字节码(词法分析,语法分析,语义分析,字节码生成码)
class文件 一个存放二进制文件,存放16进制的字节

2.2 javap

将class文件反编译为cpu指令

//原始代码
static int num = 1;
static final int a1 = 2;
int a2 = 2; 
   
//通过 javap -p -v xxx.class 反编译出来的结果
//会在堆内存中开辟一个num=0的空间
static int num;	
 	descriptor: I
 //权限
  flags: ACC_STATIC
static final int a1;
 	descriptor: I
  flags: ACC_STATIC, ACC_FINAL
  //通知虚拟机给静态变量赋值 意味着准备阶段就已经初始化值了 
  ConstantValue: int 2
  //非static变量的实例变量会随着类变量分配到java堆 在初始化阶段由类构造器初始
int a2;
 	descriptor: I

3.类加载机制

目的:将class类加载进虚拟机内存空间中

3.1 装载Loading

找到class文件所在的全路径,然后装载到内存中。具体实现由类加载器实现ClassLoader

类加载器类型总览

类加载器功能
Bootstrap ClassLoader 启动类加载器加载$JAVA_HOME中jre/lib/rt.jar里面所有的class或者Xbootclasspath选项指定的jar包
ExClassLoader 扩展类加载器加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或者-Djava.ext-dirs指定目录下的包
AppClassLoader 系统类加载器加载classpath中指定的jar包及Djava.class.path指定目录下的类和jar包
Custom ClassLoader自定义类加载器通过ClassLoader的子类自定义加载class,属于应用程序根据自身需要自定义的ClassLoader,如Tomcat,Jboss都会根据规范自行实现ClassLoader

类加载方式

  • 全盘负责
    • 只要由一个加载器负责某个类,那么这个类的父类以及子类通通由这个类加载器负责
  • 父类委托
    • 判断顶层类是否已经加载
  • 缓存机制
    • 同名的类只会被加载一次 所有必须使用到缓存

自定义类加载器 java实现

实现ClassLoader,加载类不能放到类路径下(否则会被AppClassLoader加载)

3.2 链接Linking

验证Verify:验证类的正确性
准备Prepare:为类或接口的静态字段赋值默认值

private static int a =10; 此时会先赋值默认值0

解析Resolve:动态将运行常量池中的符号引用转为直接引用(物理内存地址)

3.3 初始化Initalization

为变量附上真正的值,例如给上面的static int a赋值为10

什么情况触发初始化

  • new
  • 访问某个类或接口的静态变量
  • 调用类的静态方法
  • 反射
  • 初始化某个类的子类
  • 虚拟机指定启动类

4.JVM运行时数据区

根据前面的jvm分布结构图,分为了5个区域,栈、堆、程序计数器、方法区、本地方法栈

41. 方法区 Method Area

  • java线程共享的区域,生命周期和进程绑定
  • 存储类的元数据信息,模板信息
  • 内存不足时报OutOfMeoryError: Metespace
  • 方法区存放不会轻易改变的内容,在jdk8中又被称为元空间Metaspace
  • 运行时常量池 Run-Time Constant pool
    • String str = “hello” hello在常量池,可以被多引用
    • String str = new String(“hello”) 1.7以前hello在堆内存,1.8后String对象存放堆内存中,hello存放字符串常量池中

4.2 堆Heap

  • 虚拟机最大的一块线程共享区域,生命周期和进程绑定
  • 内存不足时报OutOfMeoryError: Java heap space,通过-Xms20M -Xmx20M设置堆内存大小
  • 类的或者成员变量的实例对象,例如new String(“hello”) String对象在堆内存
  • JDK1.8已经将String常量池从方法区移入堆中了,那么new String(“hello”) 会生成两个对象,String对象存放堆内存中,hello存放字符串常量池中,如果常量池存在则不创建

4.3 栈 Stacks

  • 线程私有,通过抢占CPU时间片来执行栈帧
  • 栈帧是最小的工作单位,方式是压栈、出栈,栈结构先进后出、后进先出
  • 递归导致栈深度不够用会报StackOverfolwError,栈帧深度默认大小1M,可以通过-Xss 128k修改
  • 栈帧压栈出栈 thread mian() -> a() ->b() -> c(),mian()一定是最后执行完的,一定是先进后出的
    在这里插入图片描述

4.4 栈帧的组成结构

public static int calc(int num1,num2){
    num1 = 2;
    int res = num1 + num2;
    return res;
}
calc(1,8);
//通过javap反编译内容 查看下calc栈帧
public static int calc(int, int);
    descriptor: (II)I
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
	 //操作数栈2个 局部变量3个 参数值2个
      stack=2, locals=3, args_size=2
         0: iconst_2	//push一个int值压入操作栈中 2
         1: istore_0	//将操作数栈的值出栈赋值给局部变量的第0个 num1=2
         2: iload_0		//第0个局部变量的值压入操作数栈 2
         3: iload_1		//第1个局部变量的值压入操作数栈 8
         4: iadd		//执行一个相加的操作 10
         5: istore_2	//将操作数栈的值出栈赋值给局部变量的第2个 res = 10
         6: iload_2		//第二个局部变量的值压操作数栈 res
         7: ireturn		//第二个局部变量出操作数栈 返回10 然后通过方法返回地址到main栈帧
  • 局部变量表,存储局部变量的
  • 操作数栈,用来保存运算的临时栈
  • 动态链接,将符号引用转为直接引用
  • 方法的返回,继续执行后面的方法

java中的一行代码,可能是多个汇编指令

4.5 程序计算器PC Register

  • 和操作系统中的寄存器一样,当线程执行过程中被其他线程抢占时间片先去执行了,需要记录正在执行的方法和位置
  • 线程私有

4.6 本地方法栈Native Method Stacks

  • 线程执行某个方法过程中需要调用本地Native方法,这类方法是没有JVM没有维护的,所以每个线程都有一个本地方法栈,调用到的地方通过链接过去

5.创建一个对象在内存中都做了什么?

  1. 先将指定的class文件加载进内存
  2. 执行main方法时,在栈内存中开辟了属于main线程的栈空间,分配给变量p
  3. new关键字向堆内存申请一个实例对象空间,分配一个内存地址值
  4. 在实例对象空间进行属性的空间分配,并进行了默认初始化
  5. 对空间中的属性动态将符号引用转为直接引用
  6. 对实例的构造代码块初始化,调用该实例类的构造方法,进行构造方法初始化
  7. 将首地址赋值给p,p变量就引用了该实例,指向了该对象

6.堆栈总结

一句话足以:垃圾堆,精华栈

以上就是本章的全部内容了。

上一篇:MongoDB第二话 – MongoDB高可用集群实现
下一篇:JVM第二话 – JVM内存模型以及垃圾回收

人寿几何?逝如朝霜。时无重至,华不再阳

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为什么要学JVM1、一切JAVA代码都运行在JVM之上,只有深入理解虚拟机才能写出更强大的代码,解决更深层次的问题。2、JVM是迈向高级工程师、架构师的必备技能,也是高薪、高职位的不二选择。3、同时,JVM又是各大软件公司笔试、面试的重中之重,据统计,头部的30家互利网公司,均将JVM作为笔试面试的内容之一。4、JVM内容庞大、并且复杂难学,通过视频学习是最快速的学习手段。课程介绍本课程包含11个大章节,总计102课时,无论是笔试、面试,还是日常工作,可以让您游刃有余。第1章 基础入门,从JVM是什么开始讲起,理解JDK、JRE、JVM的关系,java的编译流程和执行流程,让您轻松入门。第2章 字节码文件,深入剖析字节码文件的全部组成结构,以及javap和jbe可视化反解析工具的使用。第3章 类的加载、解释、编译,本章节带你深入理解类加载器的分类、范围、双亲委托策略,自己手写类加载器,理解字节码解释器、即时编译器、混合模式、热点代码检测、分层编译等核心知识。第4章 内存模型,本章节涵盖JVM内存模型的全部内容,程序计数器、虚拟机栈、本地方法栈、方法、永久代、元空间等全部内容。第5章 对象模型,本章节带你深入理解对象的创建过程、内存分配的方法、让你不再稀里糊涂。第6章 GC基础,本章节是垃圾回收的入门章节,带你了解GC回收的标准是什么,什么是可达性分析、安全点、安全,四种引用类型的使用和别等等。第7章 GC算法与收集器,本章节是垃圾回收的重点,掌握各种垃圾回收算法,分代收集策略,7种垃圾回收器的原理和使用,垃圾回收器的组合及分代收集等。第8章 GC日志详解,各种垃圾回收器的日志都是不同的,怎么样读懂各种垃圾回收日志就是本章节的内容。第9章 性能监控与故障排除,本章节实战学习jcmd、jmx、jconsul、jvisualvm、JMC、jps、jstatd、jmap、jstack、jinfo、jprofile、jhat总计12种性能监控和故障排查工具的使用。第10章 阿里巴巴Arthas在线诊断工具,这是一个特别小惊喜,教您怎样使用当前最火热的arthas调优工具,在线诊断各种JVM问题。第11章 故障排除,本章会使用实际案例讲解单点故障、高并发和垃圾回收导致的CPU过高的问题,怎样排查和解决它们。课程资料课程附带配套项目源码2个159页高清PDF理论篇课件1份89页高清PDF实战篇课件1份Unsafe源码PDF课件1份class_stats字段说明PDF文件1份jcmd Thread.print解析说明文件1份JProfiler内存工具说明文件1份字节码可视化解析工具1份GC日志可视化工具1份命令行工具cmder 1份学习方法理论篇部分推荐每天学习2课时,可以在公交地铁上用手机进行学习。实战篇部分推荐对照视频,使用配套源码,一边练习一遍学习。课程内容较多,不要一次性学太多,而是要循序渐进,坚持学习。      

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值