本文是学习了 jvm 之后对基础的简单总结,做一个简单的分享交流,本篇主要从类加载机制、jvm 内存模型、三个部分进行介绍。
上图是一个大概的运行过程,java程序经过编译后形成*.class文件,内含JVM的字节码。通过类加载器将字节码(*.class)加载入JVM的内存中。
类加载机制
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
类加载到虚拟机内存的生命周期
加载:获取定义的二进制字节流,将静态存储结构转化为方法区的运行时数据结构,在内存中生成一个java.lang.Class对象(作为方法区数据的访问入口)
数组类本身不通过类加载器创建,它是由Java虚拟机直接创建的
验证:4个阶段的检验动作:文件格式验证,元数据验证,字节码验证,符号引用验证
准备:正式为类变量分配内存并设置类变量初始值的阶段
解析:虚拟机将常量池内的符号引用替换为直接引用的过程
初始化:类加载过程的最后一步,根据计划去初始化类变量和其他资源,或者初始化阶段是执行类构造器()方法的过程
字节码执行机制
虚拟机字节码执行引擎:JVM根据Class 文件中给出的字节码指令,基于栈解释器的一种执行机制,JVM解析字节码指令,输出运行结果的一个过程
启动一个线程时,JVM就为它分配一个Java栈,栈是以帧为单位保存当前线程的运行状态的,栈是保存线程运行状态的,帧是保存方法执行的运行状态的,帧是栈的元素。线程的切换对应着栈的出栈入栈,线程中的不同方法依次运行对应着帧的出栈和入栈
运行时栈帧结构
局部变量表:方法参数和方法内定义的局部变量组成,容量以变量槽(slot)为最小单位
操作数栈:起始为空,字节码指令在栈中存数据和取数据,方法的返回值存到上一个方法的操作数据栈中
动态链接:含有一个指向常量池中该栈帧所属方法的引用,目的进行动态分派
方法返回地址:存放调用方法的PC计数器值,方法正常返回时,把返回值传递到上层方法调用者,方法异常时,通过异常处理表返回地址
方法调用
静态分派:编译时期就决定调用的方法,不是由虚拟机决定,方法的重载
动态分派:虚拟机运行阶段决定调用的方法,方法的重写
动态类型特性的支持
动态类型语言特征:类型检查发生在运行时,在编译时期不会检查
优势在于可移植性强,对底层硬件依赖不大,跨平台,但相同操作需要更多指令才能完成
jvm内存模型
JVM内存共分为虚拟机栈、程序计数器,本地方法栈、Java堆,方法区五个部分
程序计数器(线程私有): 较小的内存空间,当前线程执行的字节码的行号指示器;各线程之间独立存储,互不影响
java 虚拟机栈(线程私有):描述的是Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame )用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程
本地方法栈(线程私有):保存的是native方法的信息,当一个JVM创建的线程调用native方法后,JVM不再为其在虚拟机栈中创建栈帧,JVM只是简单地动态链接并直接调用native方法
Java堆(线程共享):被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存
方法区(线程共享):用于存储已经被虚拟机加载的类信息,常量,静态变量等,内存回收目标主要针对常量池的回收和堆类型的卸载
以上是本篇博客的全部内容,下一篇Jvm基础部分(二)将从jvm 性能监控与故障定位和、Jvm 调优、GC 垃圾回收三个部分进行介绍 ,请期待下一节