zoukankan      html  css  js  c++  java
  • JAVA JVM 杂谈(一)

    JVM能够跨计算机体系结构来执行Java字节码,主要是由于JVM屏蔽了与各个计算机平台先关的软件或者硬件之间的差异,使得与平台先关的耦合统一由JVM的提供者来实现。

    JVM结构组成:

    1.类加载器:在JVM启动时或者在类运行时将需要的class加载到JVM中。

    2.执行引擎:执行引擎的任务是负责执行class文件中包含的字节码指令,相当于实际机器上的CPU。

    3.内存区:将内存划分成若干个区以模拟实际机器上的存储、记录和调度功能模块,如实际机器上的各种功能的寄存器或者PC指针的记录器等。

    4.本地方法调用:调用C或C++实现的本地方法代码返回结果。

    一.类加载器 

    ClassLoader:

    1.负责将Class加载到JVM中。2.审查每个类该由谁加载,它是一种父优先级等级加载机制。3.将Class字节码重新解析成JVM统一要求的格式。

    JVM加载class文件到内存有两种方式

    隐式加载:所谓隐式加载就是不通过在代码里调用ClassLoader来加载需要的类,而是通过JVM来自动加载需要的类到内存的方式。例如,当我们在类中继承或者引用某个类时,JVM在解析当前这个类时发现引用的类不在内存中,那么就会自动将这些类加载到内存中。

    显示加载:相反的显示加载就是我们在代码中通过调用ClassLoader类来加载一个类的方式,例如,调用this.getClass.getClassLoader().loadClass()或者Class.forName();

    三种ClassLoader

    1.BootstrapClassLoader:主要加载JVM自身工作需要的类,这个ClassLoader完全是JVM自己控制的,需要加载哪个类、怎么加载都是由JVM自己控制,别人也访问不到这个类,它仅仅是一个类的加载工具而已,既没有更高一级的父加载器,也没有子加载器。

    2.ExtClassLoader:扩展类加载器,它会加载System.getProperty("java.ext.dirs")目录下的文件。

    3.AppClassLoader:它的父类是ExtClassLoader,所有在System.getProperty("java.class.path")目录下的类都可以被这个类加载器加载,这个目录就是经常用到的classpath。

           如果我们要实现自己的类加载器,不管你是直接实现抽象类ClassLoader,还是继承URLClassLoader类,或者其他子类,它的父加载器都是AppClassLoader,因为不管调用哪个父类构造器,创建的对象都必须最终调用getSystemClassLoader()作为父加载器。而getSystemClassLoader()方法获取的正是AppClassLoader。

    一个ClassLoader加载class到JVM中的步骤:

    第一个阶段是找到 .class文件并把这个文件包含的字节码加载到内存中。

    第二个阶段又可以分为三个步骤,分别是字节码验证、Class类数据结构分析及相应的内存分配和最后的符号表的连接。

    第三个阶段是类静态属性和初始化赋值,以及静态块的执行。

    二.执行引擎

           执行引擎是JVM的核心部分,执行引擎的作用就是解析JVM字节码指令,得到执行结果。JVM执行引擎采用什么方式实现,由实现厂家自己决定。如SUN的hotspot是基于栈的执行引擎,而Google的Dalvik是基于寄存器的执行引擎。

    三.JVM运行时数据区

          JVM虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁。

     程序计数器:它是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。程序计数器是线程私有的内存,每条线程都有一个程序计数器,这样在多线程执行线程切换回来后,才能保证恢复到正确的执行位置。如果线程正在执行的是一个JAVA方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,则计数器值则为空。此内存区域是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

    JAVA虚拟机栈:java虚拟机栈也是一个线程私有的,它的生命周期与线程相同。虚拟机栈描述的是java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。在JAVA虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将会抛出StackOverflowError异常;如果虚拟机可以动态扩展,当扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

    本地方法栈:与虚拟机栈所发挥的作用非常相似,它们之间的区别不过是虚拟机栈为虚拟机执行java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务。同样也会抛出StackOverflowError和OutOfMemoryError异常,也是一个线程私有的

    java堆:java堆是java虚拟机所管理的内存中最大的一块是被所有线程共享的一块内存区域,在虚拟机启动时创建。所有的对象实例以及数组都要在堆上分配。(java堆是垃圾收集器管理的主要区域)。

    方法区:是一个被所有线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译过后的代码等数据。当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

           运行时常量池(方法区的一部分):用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放

    未完待续。 

  • 相关阅读:
    GET请求和POST请求的本质区别
    go切片的Add与Del
    滚动到指定位置的问题
    promise---批量调用接口,等待所有的请求发完
    this argument
    html2canvas截图 下载图片
    数组合并去重
    vue项目踩坑
    关于java中的栈和堆
    用python实现一个最简单版本的mysql数据库连接池
  • 原文地址:https://www.cnblogs.com/dev1ce/p/10682991.html
Copyright © 2011-2022 走看看