zoukankan      html  css  js  c++  java
  • JVM深入理解(一) -JVM初识

    JVM深入理解(一)

    1. JVM是什么
    2. JRE、JDK和JVM 的关系
    3. JVM原理

    1、JVM是什么?

      JVM是Java Virtual Machine(Java虚拟机)的缩写,由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成

      他是帮助我们将java代码 生成编译后 的 class 文件。 

    2、JRE、JDK和JVM 的关系  

      JRE(Java Runtime Environment, Java运行环境)是Java平台,所有的程序都要在JRE下才能够运行。包括JVM和Java核心类库和支持文件。

      JDK(Java Development Kit,Java开发工具包)是用来编译、调试Java程序的开发工具包。包括Java工具(javac/java/jdb等)和Java基础的类库(java API )。

      JVM(Java Virtual Machine, Java虚拟机)是JRE的一部分。JVM主要工作是解释自己的指令集(即字节码)并映射到本地的CPU指令集和OS的系统调用。Java语               言是跨平台运行的,不同的操作系统会有不同的JVM映射规则,使之与操作系统无关,完成跨平台性。

      JDK

      JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK)。JDK 物理存在,是 programming tools、JRE 和 JVM 的一个集合。

      

      JRE

      JRE(Java Runtime Environment)Java 运行时环境,JRE 物理存在,主要由Java API 和 JVM 组成,提供了用于执行 java 应用程序最低要求的环境。

      

    3、JVM原理

      3.1、JVM的体系结构

      

      3.2、JVM生命周期介绍

      3.2.1  启动

      启动一个JAVA程序,一个JVM实例就会产生。例如我们通常用到的main() 方法一样。

      3.2.2 运行

      用main() 作为程序初始线程的起点,任何其他线程均可由该线程启动。JVM内部有两种线程:守护线程和非守护线程。

      main() 属于非守护线程,守护线程通常由JVM使用,程序可以指定创建的线程为守护线程。

      3.2.3 消亡

      当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit退出。

      JVM执行引擎实例则对应了属于用户运行程序线程它是线程级别的。

      3.3、JAVA类加载器

      Java加载类的过程:

      

      3.3.1、装载(Loading)

      负责找到二进制字节码并加载到JVM中,JVM通过类名、类所在的包名、ClassLoader完成类的加载。因此,标识一个被加载了的类:类名 + 包名 + ClassLoader实例ID。 

      3.3.2、链接(Linking)

      负责对二进制字节码的格式进行校验、初始化装载类中的静态变量以及解析类中调用的接口。

      完成校验后,JVM初始化类中的静态变量,并将其赋值为默认值。

      最后对比类中的所有属性、方法进行验证,以确保要调用的属性、方法存在,以及具备访问权限(例如private、public等),否则会造成NoSuchMethodError、    NoSuchFieldError等错误信息。

      3.3.3、初始化(Initializing)
      负责执行类中的静态初始化代码、构造器代码以及静态属性的初始化,以下四种情况初始化过程会被触发。

      3.4、JVM类加载顺序

      层级结构

      

      1.Booststrap ClassLoader

      跟ClassLoader,C++实现,JVM启动时初始化此ClassLoader,并由此完成$JAVA_HONE中jre/lib/rt.jar(Sun JDK的实现)中所有class文件的加载,这个jar中包含了java规范定义的所有接口以及实现。

      2.Extension ClassLoader

      JVM用此classloader来加载扩展功能的一些jar包

      3.System ClassLoader

      JVM用此ClassLoader来加载启动参数中指定的ClassPath中的jar包以及目录,在Sun JDK中ClassLoader对应的类名为AppClassLoader。

      4.User-Defined ClassLoader

      User-Defined ClassLoader是Java开发人员继承ClassLoader抽象类实现的ClassLoader,基于自定义的ClassLoader可用于加载非ClassPath中的jar以及目录。

      

      3.5、委派模式(Delegation Mode)

      

      当JVM加载一个类的时候,下层的加载器会将任务给上一层类加载器,上一层加载检查它的命名空间中是否已经加载这个类,如果已经加载,直接使用这个类。如果没有加载,继续往上委托直到顶部。检查之后,按照相反的顺序进行加载。如果Bootstrap加载器不到这个类,则往下委托,直到找到这个类。一个类可以被不同的类加载器加载。

      可见性限制:下层的加载器能够看到上层加载器中的类,反之则不行,委派只能从下到上

      不允许卸载类:类加载器可以加载一个类,但不能够卸载一个类。但是类加载器可以被创建或者删除。

      3.6、JVM执行引擎

      类加载器将字节码载入内存后,执行引擎以java字节码为单元,读取java字节码。java字节码机器读不懂,必须将字节码转化为平台相关的机器码。这个过程就是由执行引擎完成的。

      

      在执行方法时JVM提供了四种指令来执行

      invokestatic:调用类的static方法。

      invokevirtual:调用对象实例的方法。

      invokeinterface:将属性定义为接口来进行调用。

      invokespecial:JVM对于初始化对象(Java构造器的方法为:)以及调用对象实例的私有方法时。

      主要的执行计数:

      解释,即时执行,自适应优化、芯片级直接执行。

      解释属于第一代JVM

      即时编译JIT属于第二代JVM

      自适应优化(目前sun的HotspotJVM采用这种技术),吸取第一代JVM和第二代JVM的经验,采用两者结合的方式,开始对所有的代码都采用解释执行的方式,并监视代码执行情况,然后对那些经常调用的方法启动一个后台线程,将其编译为本地代码,并进行优化。若方法不再频繁使用,则取消编译过代码,仍对其进行解释执行。

      

      3.7、Java运行时数据区

      

      PC寄存器

      用于存储每个线程下一步将要执行的JVM指令,若该方法为native的,则PC寄存器中不存储任何信息。Java多线程情况下,每个线程都有一个自己的PC,以便完成不同线程上下文环境的切换

      JVM栈 

    JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放当前线程中局部基本类型的变量(Java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆的地址。

      堆(Heap)

    它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。

    堆在JVM启动的时候就被创建,堆中储存了各种对象,这些对象被自动管理内存系统(Automatic Storage Management System),也就是常说的“Garbage Collector(垃圾回收器)”管理。这些对象无需、也无法显示地被销毁。

    JVM将Heap分为两块:新生代New Generation和旧生代Old Generation

        

      堆是JVM中所有线程共享的,因此在其上进行对象内存的分配均需要进行加锁,导致new对象的开销比较大。

      Sun Hotspot JVM为了提升对象内存分配的效率,对于所有创建的线程都会分配一块独立的空间TLAB(Thread Local Allocation Buffer),其大小由JVM根据运行的情况计算而得,在TLAB上分配对象时不需要加锁,因此JVM在给线程对象分配内存时会尽量的在TLAB上分配,在这种情况下JVM中分配对象内存的性能和C基本是一样的,但如果对象过大的话则仍然要直接使用堆空间分配。

      TLAB仅作用于新生代的Eden Space,因此在编写Java程序时,通常多个小的对象比大的对象分配起来更加高效。

      所有新创建的Object都将会存储在新生代Young Generation中。如果Young Generation的数据在一次或多次GC后存活下来,那么将被转移到OldGeneration。新的Object总是创建在Eden Space。

      方法区域(Method Area)

      在Sun JDK中这块区域对应的为PermanetGeneration,又称为持久代。

      方法区域存放所加载类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName,isInstance等方法来获取信息时,这些数据都来源于方法区域,同时方法区域也是全局共享的,在一定条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,就会抛出OutOfMemory的错误信息。

      运行时常量池(Runtime Constant Pool)

    存放的为类中的固定常量信息、方法和Field的引用信息等,其空间从方法区域中分配。

      本地方法堆栈(Native Method Stacks)

    JVM采用本地方法堆来支持native方法的执行,此区域用于存储每个native方法调用的状态。

      
      3.8、JVM垃圾回收

      GC的基本原理:将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对对象生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停。

      对新生代的对象收集称为minor GC

      对旧生代的对象收集称为Full GC

      程序中主动调用System.gc()强制执行的GC为Full GC。

      不同的对象引用类型,GC会采用不同的方法进行回收,JVM对象的引用分为了四种类型

      强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用时, GC时才会被回收)

      软引用:软引用是Java中提供的一种比较适合于缓存场景的应用(只有内存不够的情况下才会被GC)

      弱引用:在GC时一定会被GC回收。

      虚引用:虚引用只是用来得知对象是否被GC。

    来源参考:https://www.jianshu.com/p/fabad9250b1b
  • 相关阅读:
    HOJ 2139 Spiderman's workout(动态规划)
    FZU 2107 Hua Rong Dao(dfs)
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
  • 原文地址:https://www.cnblogs.com/tuanz/p/15127426.html
Copyright © 2011-2022 走看看