写点什么

9.2JVM 虚拟机架构原理

用户头像
张荣召
关注
发布于: 2020 年 11 月 22 日

1.JVM虚拟机组成架构

Java是一种跨平台的语言,JVM屏蔽了底层系统的不同,为Java字节码文件构成了一个统一的环境。



java主程序:   java   org.apache.catalina.startup.Bootstrap  "$@" start       ------tomcat启动类

命令解析: 1. java:java可执行程序,启动JVM进程

                  2. org.apache.catalina.startup.Bootstrap:Class类文件。二进制.class文件。

                  3."$@" start :作为参数提交给class类的main函数

JVM执行解析:

              1.启动JVM进程: java命令 

              2.加载类文件:通过类加载器加载类文件。比如:org.apache.catalina.startup.Bootstrap

              3.加载到运行期数据区:将类文件加载到方法区(线程共享区)。

              4.JVM创建主线程:JVM创建主线程,并为主线程分配JAVA栈和程序计数寄存器。

              5.程序计数寄存器:记录方法区可执行字节码指令的位置。

              6.执行引擎获取可执行字节码指令:java class的字节码指令,将字节码指令解释或者编译为本地操作系统的指令,因为JVM是跨平台的,可以再不同的操作系统上,不同的CPU硬件上去执行。同样的.class文件可以再不同操作系统,不同硬件上执行,就是要靠执行引擎,把.class字节码指令转换成本地的执行指令。

              7.创建对象: 在字节码执行过程中,需要创建一个对象。创建的对象放在堆里面。new指令,存放在方法区中的一行字节码指令。 指令由线程执行,创建完成的对象存放在堆中。而对象的变量引用存放在线程栈上。   

2.JVM字节码文件

      Java如何实现在不同操作系统上,不同硬件平台上,都可以不用修改代码就能顺畅的执行?

      计算机领域的任何问题都可以通过增加个中间层(虚拟层)来解决

      Java所有的指令有200个左右,一个字节(8位)可以存储256种不同的指令信息,一个这样的字节成为字节码(Bytecode)。

      在代码的执行过程中,JVM将字节码解释执行,屏蔽对低层操作的依赖,JVM也可以将字节码编译执行,如果是热点代码,

      会通过JIT动态的编译为机器码,提高执行效率。 





3.字节码执行流程



4.Java字节码文件编译过程



4.类加载器的双亲委派模型

低层次的当前类加载器,不能覆盖更高层次类加载器已经加载的类。

如果低层次的类加载器想加载一个未知类,需要上级类加载器确认,只有当上级类加载器没有加载过这个类,也允许加载的时候,

才让当前类加载器加载这个位置类。



5.自定义类加载器

  隔离加载类:同一个JVM中不同组件加载同一个类的不同版本。Tomcat加载多个Web应用。

  扩展加载源:从网络,数据库等处加载字节码。

  字节码加密:加载自定义的加密字节码,在ClassLoader中解密。

  public class CustomClassLoader extends ClassLoader{

       @Override

        protected Class<?>  findClass(String name)throws ClassNotFoundException{

                 try{

                         byte[] result=getClassFromCustomPath(name);

                         if(result==null){

                                throw new FileNotFoundException();

                         }else{

                                return defineClass(name,result,0,result.length);

                         }

                 }catch(Exception e){

                     e.printStackTrace();

                 }

                 throw new ClassNotFoundException(name);

        }



        private byte[] getClassFromCustomPath(String name){

               //从自定义路径中加载指定类

        }

  } 



  public static void main(String[] args){

        CustomClassLoader customClassLoader=new CustomClassLoader();

        try{

               Class<?> clazz=Class.forName("one",true,customClassLoader);

               Object obj=class.newInstance();

               System.out.println(obj.getClass().getClassLoader());

         }catch(Exception e){

              e.printStackTrace();

        }

  }



6.堆 & 栈

堆:每个JVM实例唯一对应一个堆,应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所拥有的所有线程共享。

堆栈:JVM为每个新创建的线程都分配一个堆栈。也就是说,对于每个JAVA线程来说,它的运行就是通过对堆栈的操作来完成的。

Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配。也就是说在建立一个对象时从两个地方分配内存,

在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的引用而已。



7.方法区 & 程序计数器

方法区:主要存放从磁盘加载进来的类字节码,而在程序运行过程中创建的类实例则存放在堆里。程序运行的时候,实际上是以线程为单位运行的。

当JVM进入启动类的main方法的时候,就会为应用程序创建主线程,main方法里的代码就会被这个主线程执行。每个线程有自己的Java栈,栈里存放着

方法运行期的局部变量。而当前线程执行到哪一行字节码指令,这个信息责备存放在程序计数寄存器。

public class Demo01{

    public static void main(String[] args){

         A a=new A();

         System.out.println(a.width);

    }

}

class A{

     public static int width=100;

     static {

           System.out.println("静态初始化类A");

           width=300;

     } 

     public A(){

           System.out.println("创建A类的对象");

     }

}



8.Java(线程)栈

所有在方法内定义的基本类型变量,都会被每个运行这个方法的线程放入自己的栈中,线程的栈彼此隔离,所以这些变量一定是线程安全的。







9.线程工作内存 & volatile

 Java内存模型规定在多线程情况下,线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行。

 

 一个共享变量(类的成员变量,类的静态成员变量)被volatile修饰之后,保证了不同线程对这个变量进行操作时的可见性,

 即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。



10.Java运行环境





用户头像

张荣召

关注

还未添加个人签名 2018.05.02 加入

还未添加个人简介

评论

发布
暂无评论
9.2JVM虚拟机架构原理