zoukankan      html  css  js  c++  java
  • JVM基础结构与字节码执行引擎

    JVM基础结构

    JVM内部结构如下:栈、堆。
    file

    JVM中的栈主要是指线程里面的栈,里面有方法栈、native方法栈、PC寄存器等等;每个方法栈是由栈帧组成的;每个栈帧是由局部变量表、操作数栈等组成。

    每个栈帧其实就代表一个方法

    java中所有对象都在堆中分配;堆中对象又分为年轻代、老年代等等,不同代的对象使用不同垃圾回收算法。

    -XMs:启动虚拟机预留的内存
    -Xmx:最大的堆内存

    一、堆的分代假设

    根据研究表明,堆中对象大部分都是创建后,立马就可以被销毁的。如:
    Plumbr_Handbook_Java_Garbage_Collection

    为了优化堆中的内存,将堆中对象分为不同代。在年轻代中,GC发生比较频繁;在老年代中,GC发生比较少。

    二、堆的分代

    • 年轻代:Young Generation
    • 老年代:Old Generation/Tenured
    • 永久代:Permanent Generation

    永久代在Java虚拟机规范中是没有的,但是Host Spot虚拟机中有。
    file

    三、方法区

    方法区被所有线程共享;方法区是用来存储编译后的代码,即存储每个类的运行时常量池、字段和方法。
    方法区在虚拟机启动时创建;虽然方法区在逻辑上是堆的一部分,但在一些简单的实现中,方法区可以选择不进行垃圾回收和紧凑化。

    方法区在java8的变化

    • java7之前:方法区的实现:永久代,是作为堆的一部分;
    • java8之后:方法区的实现:metaspace,是堆外的内存;

    1、为什么要这样改变?
    因为java可以动态加载字节码信息,这样方法区就会慢慢的挤占堆中内存。为了避免与堆争抢内存,java8将方法区的实现移至堆外。
    2、方法区、永久代、MetaSpace的区别?
    方法区是java虚拟机规范所规定的一个概念。其中java7实现方法区的地方称为永久代;java8实现方法区的地方称为MetaSpace


    字节码文件的结构

    java程序在运行的时候,将源码编译成字节码,字节码在不同系统上的JVM翻译成对应的机器码。这是Java平台无关性的基础
    file

    但是,编译后的字节码是如何读取到JVM中的?字节码执行引擎是如何识别、执行指令?
    file

    1、如何查看字节码文件

    • classpy工具
    • IDEAjclasslib Bytecode viewer插件

    2、字节码文件结构
    一个字节码文件包含以下部分:
    file
    (1)magic:0xCAFEBABE
    class文件的magic code,用于标识该文件是class文件。

    (2)minor_versionmajor_version
    用于标识该class文件的版本,防止高版本的class文件被低版本的JVM读取并执行。

    (3)constant_pool:常量池
    用于存储该class文件经常被使用的信息,优化内存。比如说System.out.print()

    (4)access_flag
    表示这个类得访问权限,对应到java源码就是publicfinal之类的


    字节码执行引擎

    这里以一个线程为例。一般来说,一个方法栈最底层的栈帧都是Thread.run方法。当一个线程准备调用另一个方法时,会先将实参拷贝一份到新栈帧的局部变量表里,然后再执行代码。
    1、局部变量表
    每次调用新方法时,会默认将当前对象的地址this作为局部变量表的第一个参数;后面存放传过来的参数。这与javascript的做法很相似。

    2、方法调用的相关指令

    • invokevirtual:一般实例方法,有多态;
    • invokeinterface:接口方法,有多态
    • invokestatuc:静态方法,无多态
    • invokespecial:特殊方法,无多态
    • invokedynamic:动态调用,JDK7新增,方法无需在编译时确定

    3、方法调用的过程
    (1)在开始时

    • 方法栈新增一个栈帧;
    • 实例方法的this、参数放到局部变量表中;
    • 开始新栈帧中字节码的执行;

    (2)在返回时

    • 将返回值放在调用者方法栈帧中的操作数栈上;

    (3)在异常出现时

    • 寻找匹配的异常处理代码

    (4)在finally

    • 为每个分支新增一个跳转

    4、为什么MockitoEasyMock无法对privatestatic方法进行mock
    因为他们mock方法是通过覆盖这些方法来实现的,而privatestatic没法被覆盖。PowerMock是通过修改字节码文件达到mock私有、静态方法的。

    原博客地址

  • 相关阅读:
    htnl类名命规范
    JAVA集合中泛型的原理本质简介
    java 泛型中的上界(extend)和下界(super)
    elasticsearch深度分页问题
    AOP组合使用切面和自定义注解
    G1垃圾回收器基本知识及原理解析
    MyBatisplus源码解析
    生产环境碰到系统CPU飙高和频繁GC,你要怎么排查?
    fullgc触发条件_记一次生产频繁出现 Full GC 的 GC日志图文详解
    JavaThreadContextLoader(线程上线文类加载器)总结
  • 原文地址:https://www.cnblogs.com/fourther/p/12673213.html
Copyright © 2011-2022 走看看