精华内容
下载资源
问答
  • 在JDK目录下,进行编译: # 生成配置 bash configure --enable-debug --with-jvm-variants=server # 开始编译(在我的机子上,大概花了25分钟) make images Clion调试 下载 CLion 2019.x ,任意19版本就行,不要用...

    本机环境

    笔记本电脑,Win10,8G内存,双硬盘,独立显卡(N卡)。

    因为平时部分软件需要使用 Windows 10 运行,所以我选择搭建双系统环境。

    操作流程

    安装OS

    这部分教程网上很多,例如:Ubuntu18.04安装教程

    因为我的笔记本是独立显卡,且双硬盘(WIN装在A硬盘,因为空间问题需要把Ubuntu装B硬盘),以下为我个人电脑的安装双系统的过程。

    1. 通过官网下载 Ubuntu 18.04.5 LTS,并使用 UltralSO 制作启动盘。

    2. 插上U盘,切换Boot,进入安装界面时按e修改quite splash

    3. 安装完毕,重启后进入Win10系统,此时无法进入Ubuntu,需安装 EasyUEFI 修改启动。

      1. 使用 EasyUEFI 添加 Ubuntu 启动;
        设置1

      2. 禁用Win10的启动,注意:这步是必须的,Win10的启动太霸道了,不禁不行。并且每次进入Win10都会把我设置的Ubuntu启动抹了;
        设置2

    4. 因为N卡的缘故,在重启后的boot界面仍然需要按e进入编辑界面,修改quite splash,可进入Ubuntu系统后用以下方式修改配置永久解决;

      sudo gedit /etc/default/grub
      
      ## 找到下方内容
      GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
      ## 改为以下内容
      GRUB_CMDLINE_LINUX_DEFAULT="quiet splash acpi_osi=linux nomodeset"
      
    5. (可选)如果安装时选择的语言是英文,进入系统后记得去“Settings-Region & Language”中更新一下语言包,否则没有中文输入法。更新完后重启即可生效。

    构建JDK12编译环境

    1. 根据书中链接,或者java官方地址,下载 JDK12,并解压;

    2. 安装环境:

      ## GCC
      sudo apt-get install build-essential;
      
      ## OpenJDK 编译依赖库
      # FreeType
      sudo apt-get install libfreetype6-dev;
      # CUPS
      sudo apt-get install libcups2-dev;
      # X11
      sudo apt-get install libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev;
      # ALSA
      sudo apt-get install libasound2-dev;
      # libffi
      sudo apt-get install libffi-dev;
      # Autoconf
      sudo apt-get install autoconf;
      
      ## OpenJDK 11
      sudo apt-get install openjdk-11-jdk;
      
      ## 书中的错误提示
      sudo apt-get install libfontconfig1-dev;
      
    3. 在JDK目录下,进行编译:

      # 生成配置
      bash configure --enable-debug --with-jvm-variants=server
      # 开始编译(在我的机子上,大概花了25分钟)
      make images
      

    Clion调试

    1. 下载 CLion 2019.x ,任意19版本就行,不要用新的版本,找不到对应按钮;

    2. 使用 CLion 的 “New CMake Project from Sources” 添加编译生成的 JDK12;

    3. 添加"CMake Appkication";

      • Executable:选择 build/XX/jdk/bin/java;
      • Program arguments:-version -XX:TraceBytecodes -XX:StopInterpreterAt=<n>;
      • 删除 build;
        在这里插入图片描述
    4. 开始调试,找到src/java.base/share/native/libjli/java.c,对应书中395行的位置打个断点,即可开始Debug。
      实验结果

    展开全文
  • 深入理解JVM虚拟机

    2021-06-27 15:54:35
    首先使用javac命令将.java文件编译成字节码文件也就是.class文件,之后交给JVM虚拟机去执行,从而转换成特定平台的执行指令,这也是为什么一份相同的.class文件可以在不同的操作系统上运行的原因,下图是一张java...

    一、Compile Once,Run Anywhere如何实现

    首先使用javac命令将.java文件编译成字节码文件也就是.class文件,之后交给JVM虚拟机去执行,从而转换成特定平台的执行指令,这也是为什么一份相同的.class文件可以在不同的操作系统上运行的原因,下图是一张java项目从编译到执行的流程图:
    在这里插入图片描述

    二、JVM如何加载.class文件

    下图为java虚拟机的运行结构,分别由Class Loader、Execution Engine、Native Interface和Runtime Data Area组成,首先由Class Loader会读取特定格式的class文件,然后交给Execution Engine来对其解析,解析完成之后在通过Native Interface融合一些第三方类库,最后放到Runtime Data Area去运行即可;

    Class Loader:依据特定格式,加载class文件到内存中;
    Execution Engine:对命令进行解析;
    Native Interface:融合不同语言的开发库为Java所用;
    Runtime Data Area:JVM内存空间结构;
    在这里插入图片描述

    三、问类从编译到执行一共需要几步?

    假设现在有一个Demo.java文件,那它从编译到执行总共只需要三步即可:

    1.编译器将Demo.java文件编译成Demo.class字节码文件;
    2.ClassLoader将字节码转换为JVM中的Class(Demo)对象;
    3.JVM利用Class(Demo)对象实例化为Demo对象;

    四、ClassLoader到底是啥?

    ClassLoader在Java中有这非常重要的作用,它主要工作在Class装载的加载阶段,其主要作用是从系统外部获得Class二进制数据流。他是Java的核心组件,所有的Class都是由ClassLoader进行加载的,ClassLoader负责通过将Class文件里的二进制数据流装载进系统,然后交给Java虚拟机进行连接、初始化等操作。

    五、ClassLoader种类

    BootStrapClassLoader:C++编写,加载核心库java.*
    ExtClassLoader:Java编写,加载扩展库javax.*
    AppClassLoader:Java编写,加载程序所在目录
    自定义ClassLoader:Java编写,定制化加载

    六、自定义ClassLoader实战

    理论讲的在多,还是不懂啥是ClassLoader,该怎么用,那么接下来博主带领大家编写自己人生中的第一个ClassLoader(是不是第一无所谓0.0),让你感受Java真正的魅力:

    首先创建一个.java文件,放置在项目以外,然后将该文件编译成.class字节码,下图为.java文件内容:

    public class ClassLoaderDemo {
    	//.java文件内容只需要一个static代码块即可,当该类在进行实例化时会自动执行代码块中的内容;
        static{
            System.out.println("Hello, I'm loaded by a custom classloader");
        }
    }
    

    字节码文件地址如下图,项目在RocketMQ中(不要问为什么在这里面,我也不知道):
    在这里插入图片描述
    接着就是编写我们自己的ClassLoader啦(有点小激动):

    package com.intretech.classloader;
    
    import java.io.*;
    
    /**
     * 自定义ClassLoader
     * 主要实现两个方法即可:
     * 第一个是findClass方法,用于加载.class字节码文件
     * 第二个是defineClass方法,用于定义Class,当前自定义ClassLoader使用默认实现的方式即可
     */
    public class MyClassLoader extends ClassLoader{
    
        private String name;
        private String path;
    
        public MyClassLoader(String name,String path){
            this.name=name;
            this.path=path;
        }
    
        /**
         * 寻找需要加载的.class字节码文件
         * @param name .class字节码文件的名称
         * @return
         */
        @Override
        public Class findClass(String name){
            //加载.class字节码文件
            byte[] b=loaderClassData(name);
    
            //使用ClassLoader默认实现好的定义Class方法即可
            return defineClass(name,b,0,b.length);
        }
    
        /**
         * 加载.class字节码文件
         * @param name .class字节码文件的名称
         * @return
         */
        private byte[] loaderClassData(String name) {
            name = path+name+".class";
            InputStream in=null;
            ByteArrayOutputStream out=null;
            try{
                in = new FileInputStream(new File(name));
                out = new ByteArrayOutputStream();
                int i=0;
                while ((i =in.read())!= -1){
                    out.write(i);
                }
                return out.toByteArray();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                try {
                    in.close();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }
    

    自定义ClassLoader写好了,接下来咱们来使用他吧:

    package com.intretech.classloader;
    
    /**
     * 自定义ClassLoader测试使用类
     */
    public class MyClassLoaderTest {
        
        public static void main(String[] args) throws IllegalAccessException, InstantiationException {
            //创建MyClassLoader对象,name随便填,只是个名称,path填需要加载的.class文件所在地址
            MyClassLoader myClassLoader = new MyClassLoader("myClassLoader", "F:\\YQ\\HolyGrail\\");
    
            //通过findClass定义出ClassLoaderDemo类
            Class classLoaderDemo = myClassLoader.findClass("ClassLoaderDemo");
    
            //实例化对象,并且会执行static代码块中的内容;即会在控制台打印"Hello, I'm loaded by a custom classloader"
            classLoaderDemo.newInstance();
        }
    
    }
    

    很简单吧,其实就是先通过findClass方法将.class文件加载成byte[],然后交给defineClass方法去执行得到对应的类,得到类之后就能为所欲为了0.0;

    七、ClassLoader的双亲委派机制

    加载一个类是有规则的,不是一通乱加载,首先是自底向上的,先从Customer ClassLoader查找是否加载过该类,有的话直接返回就好了,如果没有,那就交给他的上级,也就是App ClassLoader去查找,以此类推,一直到最顶层的Bootstrap ClassLoader,如果都没有加载过(好家伙,新来的),这时候就开始另一种方式了,也就是图中自项向下去尝试加载,首先是Bootstrap ClassLoader(因为现在球在它这嘛,所以当然是他先了),Bootstrap ClassLoader会去rt.jar中或者是指定的jar(这个位置可以自定义哦,方式就是启动jar包的时候加上-Xbootclasspath “路径”)去查找这个类,如果找到了这个类,那就加载完返回即可,如果没有,那就交给下级,去它们自己负责的路径里面查找有没有这个类,以此类推,如果说最终都没有找到这个类,好了,别启动了,直接给老子报异常,ClassNotFoundException,老老实实去解决吧。
    在这里插入图片描述
    说了一大堆,可能有些小伙伴没有听懂,没有关系,接下来咱们通过一段代码来看看ClassLoader到底是怎么加载的,是不是和上图的方式一致的,看下博主到底有没有在瞎说(也不是没有可能,所以下面一段代码认真看哦):

     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
     		//加锁
            synchronized(this.getClassLoadingLock(name)) {
            	//先让当前ClassLoader去查找,是否有加载过该类
                Class<?> c = this.findLoadedClass(name);
                //没有的话,那就进来吧你
                if (c == null) {
                    long t0 = System.nanoTime();
    
                    try {
                    	//先判断是否有上级,也就是判断当前的ClassLoader是不是Bootstrap ClassLoader
                        if (this.parent != null) {
                        	//上级不为空,好办,让上级去查找
                            c = this.parent.loadClass(name, false);
                        } else {
                        	//上级为空了,说明是Bootstrap ClassLoader,那就专门调用orNull方法了
                        	//因为如果在没有找到说明就没有加载过嘛,当然就得返回null了
                            c = this.findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException var10) {
                    }
    				//因为上面第一种方式没有找到该类,接下来开始第二种方式了
                    if (c == null) {
                        long t1 = System.nanoTime();
                        //通过自项向下的方式去尝试加载该类了
                        c = this.findClass(name);
                        PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        PerfCounter.getFindClasses().increment();
                    }
                }
    
                if (resolve) {
                    this.resolveClass(c);
                }
                
                return c;
            }
        }
    

    这个注释加的可以吧,这下应该知道博主没有在瞎说了吧!0.0

    八、loadClass和forName的区别

    这两个家伙都是显式加载类的方式,你们如果不认识,那你们一定认识他们的亲兄弟——new,new是隐式加载类的方式,new出来的实例可以直接使用,而loadClass和forName加载的类需要在通过newInstance方法得到对应的实例才可使用,言归正传,那loadClass和forName到底有什么区别呢,咱们先了解一下类的装载过程(也有人叫加载过程,一样的):
    如下图,类的装载过程分为三步,loadClass装载类时只会到第二步,而forName会到第三步,这就是他们的区别,也就是loadClass不会初始化,而forName会。
    在这里插入图片描述
    可能你们又认为博主在乱说,接下来上证据:

    首先上的是loadClass源码,可以发现,resolve默认传的false,所以不会去执行resolveClass方法,这个方法从注释上来看就知道是要链接该类的意思,所以,loadClass在加载一个类时,只会进行到链接,根本到不了初始化;

    public Class<?> loadClass(String name) throws ClassNotFoundException {
            return loadClass(name, false);
    }
    
    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    try {
                        if (parent != null) {
                            c = parent.loadClass(name, false);
                        } else {
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {
                        // ClassNotFoundException thrown if class not found
                        // from the non-null parent class loader
                    }
    
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        long t1 = System.nanoTime();
                        c = findClass(name);
    
                        // this is the defining class loader; record the stats
                        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        sun.misc.PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    
    /**
         * Links the specified class.  This (misleadingly named) method may be
         * used by a class loader to link a class.  If the class <tt>c</tt> has
         * already been linked, then this method simply returns. Otherwise, the
         * class is linked as described in the "Execution" chapter of
         * <cite>The Java&trade; Language Specification</cite>.
         *
         * @param  c
         *         The class to link
         *
         * @throws  NullPointerException
         *          If <tt>c</tt> is <tt>null</tt>.
         *
         * @see  #defineClass(String, byte[], int, int)
         */
        protected final void resolveClass(Class<?> c) {
            resolveClass0(c);
        }
    

    我们在来看下forName的源码:
    重点关注initialize这个参数,它代表着是否要初始化,默认传的是true,所以我们可以清楚的判断出来forName加载类时是会进行初始化的;
    在这里插入图片描述
    有些小伙伴这时候会提问了,为什么需要有这两种方式,直接弄一种初始化的不就好了吗?(好问题),这是因为这两种方式都各有大用,比方说你在加载jdbc驱动时,你就需要去加载源码中的静态代码块,这时你就需要使用forName,loadClass在Spring IOC中则被大量使用,因为Spring IOC为了加快加载速度,使用了大量的懒加载,所以loadClass在加载速度方面的优势就提现出来了,所以我们可以知道一个道理:存在即合理;

    九、Java内存模型

    咱们先来看看一张老图,请各位小伙伴先思考一下,Java内存模型指的是下图中的哪个部分(等待10秒),聪明的小伙伴应该已经找到了,就是Runtime Data Area(你找对了吗);
    在这里插入图片描述
    上图仅仅是个开胃菜,想要真正搞懂Java内存模型还需要继续深入,本章使用JDK8的Java内存模型来讲解(其实后面的JDK9,JDK10…都是类似的),我们可以从两个角度去理解,一个是线程的角度,另一个就是存储的角度,咱们先从线程的角度来see see;

    如下图所示,线程可以分为线程私有和线程共享,像程序计数器、虚拟机栈、本地方法栈属于线程私有的,每个线程对应一个,而MetaSpace(元空间)、常量池和堆就属于线程共享的了,所有线程一起使用,看到这,详细大家都有同一个感觉就是:“懂了,但没完全懂”,没关系,博主接下来为各位小伙伴解释一下它们到底是个什么鬼;

    程序计数器(Program Counter Register):当前线程所执行的字节码行号指示器(逻辑计数器),通俗点说,就是记录当前线程运行到第几行代码了,如果需要执行下一行代码,那就改变计数器的值就可以了,因为cpu在特定时间只能处理一个线程(所谓的多线程其实是cpu在不停的切换线程执行,速度快到让你认为是在一起执行,但其实实质上还是单线程,除非你是多核),所以为了记录每个线程的执行位置,程序计数器和线程都是一对一关系即“线程私有”,并且线程技术器只对Java方法计数,如果是Native修饰的方法计数器的值为Undefined,因为计数器只几率行号,所以根本不用担心内存泄露问题哦!

    虚拟机栈(Stack):Java方法执行的内存模型,包含多个栈帧,栈帧用于存储局部变量表,操作栈,动态链接和方法出口等信息,当调用方法结束了,栈帧就会被删除,局部变量表包含方法执行过程中的所有变量,操作数栈包括入栈、出栈、复制、交换、产生消费变量的操作,大部分jvm字节码都把时间消耗在操作数栈的操作上,栈是一个后进先出的数据结构,除了入栈和出栈,栈帧不能直接被操作;

    本地方法栈:和虚拟机栈是类似是,不同的是本地方法栈是作用于有native修饰的方法,比如上文说的forName方法使用的就是本地方法栈;

    MetaSpace(元空间):所有线程共享,存储类的加载信息;

    堆(Heap):所有线程共享,主要是用来存放对象实例,同时也是GC管理的主要区域;
    在这里插入图片描述

    展开全文
  • java语言被称为跨平台的语言,而JVM可以被称之为跨语言的平台。只要是可以编译成class文件的语言都可以把classwen'ji

           JVM虚拟机class文件结构和加载过程

            java语言被称为跨平台的语言,而JVM可以被称之为跨语言的平台。很多语言如java,scala,kotlin,groovy,clojure,jython,jruby等等这些都可以编译成class文件。所以可以说JVM与java无关,任何语言只要可以编译成class文件就可以在jvm上运行。

           想要了解JVM那么首先需要了解java从编码到执行的过程。首先如我们前面所说xxx.java要经过javac编译成.class。然后通过ClassLoader load到内存,然后虚拟机还会把java类库也load到内存。因为java是编译和解释混合执行,接下来会分析热点代码编译执行,普通代码解释执行最后通过执行引擎执行写入硬件。可以用一张图来描述

     class文件是JVM运行的基础,那么先让我们来熟悉一下class文件的结构通常我们看到的是class文件16进制的格式我们来分析一下他的结构

    从版本号到常量池个数到常量池,代表方法接口class类名等。

           接下来我们要了解一下JVM加载类的过程。整个过程分为三个Loading、Linking、Initializing

    Linking又分为Verification,Preparation,Resolusion

          1.loading

    loading的过程是采用双亲委派机制。当需要加载一个class的时候当前类的Classloader会查询是否加载过,如果没有会委托父加载器检查(注意父加载器不是父类的加载器他们没有继承关系)。一直到最上面的Bootstrap如果没有在往下委派加载一直到能够把类加载进来。如果到最后也没能完成加载则抛出classNotfound异常

    加载器的层次关系如下

    双亲委派机制是Classloader的loadclass方法写好的逻辑。如果我们想要用自定义的classloader则需要重写findClass方法。而有些时候比如tomcat的热部署则需要打破双亲委派机制这时候我们就需要重写loadclass方法了。

          2.Linking

    进入到linking阶段,首先要对class文件进行校验Verification。如果不符合JVM规范则会在这个阶段返回异常。然后通过Preparation阶段将静态变量赋默认值。Resolusion阶段将符号引用解析为具体地址引用。

        3.Initializing最后Initializing则将静态变量赋初始值也就是初始化的过程。

     

    展开全文
  • 在讲解 JVM 虚拟机知识之前,我们有必要先弄清它的概念。 很多程序员已经干了一段时间 Java 开发了依然不明白 JDK、JRE、JVM 的区别,现在我们就捋一捋: 概念: JDK(Java Development Kit):Java 语言的软件...

    在讲解 JVM 虚拟机知识之前,我们有必要先弄清它的概念。

    很多程序员已经干了一段时间 Java 开发了依然不明白 JDK、JRE、JVM 的区别,现在我们就捋一捋:

    概念:

    JDK(Java Development Kit):Java 语言的软件开发工具包(SDK),是整个JAVA的核心,是面向 Java 程序的开发者,提供了 Java 的运行环境(Java Runtime Envirnment)和开发环境 -- 一堆Java工具(javac/java/jdb等)和Java基础的类库(即Java API 包括rt.jar)。SDK是Software Development Kit 一般指软件开发包,可以包括函数库、编译程序等。

    JDK在目录下面有 六个文件夹、一个src类库源码压缩包、和其他几个声明文件。其中,真正在运行 Java 时起作用的是以下四个文件夹:bin、include、lib、 jre。

    • bin:最主要的是编译器(javac.exe)
    • include:java和JVM交互用的头文件
    • lib:类库
    • jre:java运行环境

    JRE(Java Runtime Enviroment):是指Java的运行环境,是面向Java程序的使用者,而不是开发者(若果只想运行 Java 的.class文件,只需要安装JRE就可以了)。它包含 JVM 标准实现及 Java 核心类库,因为并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器)。
    JRE是指java运行环境。光有JVM还不能成class的 执行,因为在解释class的时候JVM需要调用解释所需要的类库lib。 (jre里有运行.class的java.exe)
    JRE 是运行 Java 程序必不可少的,它的地位就象一台PC机一样,我们写好的 Win64 应用程序需要操作系统帮们运行。同样的,我们编写的 Java 程序也必须要 JRE 才能运行,因为在解释 .class 文件的时候 JVM 需要调用解释所需要的类库lib(JRE 里有运行.class的java.exe)。

    总的来说 JDK 是用于 Java 程序的开发,而 JRE 则是只能运行 class 而没有编译的功能。

    JVM(Java Virtual Machine):Java虚拟机,它是整个 Java 实现跨平台的最核心的部分,所有的 Java 程序会首先被编译为 .class 的类文件,这种类文件可以在虚拟机上执行,也就是说 class 并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。
    JVM 是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。针对 Java 用户,也就是拥有可运行的 .class 文件包(jar或者war)的用户。里面主要包含了 JVM 和 Java 运行时基本类库(rt.jar)。

    rt.jar 可以简单粗暴地理解为:它就是 Java 源码编译成的 jar 包。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够 “一次编译,到处运行” 的原因。

    通过上面这张图,会帮助我们理解的更加直观。

    有这样一个关系,JDK 包含 JRE,而 JRE 包 含JVM,详细点就是 :

    • JDK 包括编译器(javac.exe)、开发工具(javadoc.exe、jar.exe、keytool.exe、jconsole.exe)和更多的类库(如tools.jar)等;
    • JRE 包括 JVM 虚拟机(java.exe等)和基本的类库(rt.jar等),用来支撑Java程序的运行;

    区别和联系:

    三者联系:

    1. JVM 不能单独搞定class的执行,解释 class 的时候 JVM 需要调用解释所需要的类库lib。
    2. 在JDK下面的的 jre 目录里面有两个文件夹 bin 和 lib,在这里可以认为 bin 里的就是 jvm,lib 中则是 jvm 工作所需要的类库,而 jvm 和 lib 和起来就称为 jre,即:JVM + Lib =J RE。
    3. 总体来说就是,我们利用 JDK(调用 JAVA API)开发了属于我们自己的 JAVA 程序后,通过 JDK 中的编译程序(javac)将我们的文本 java 文件编译成 JAVA 字节码,在 JRE 上运行这些 JAVA 字节码,JVM 解析这些字节码,映射到 CPU 指令集或 OS 的系统调用。

    三者区别:

    1. JDK 和 JRE 区别:在 bin 文件夹下会发现,JDK 有javac.exe 而J RE 里面没有,javac 指令是用来将 Java 文件编译成 class 文件的,这是开发者需要的,而用户(只需要运行的人)是不需要的。JDK 还有 jar.exe,javadoc.exe 等用于开发的可执行指令文件。这也证实了一个是开发环境(JDK),一个是运行环境(JRE)。
    2. JRE 和 JVM 区别:JVM 并不代表就可以执行 class 了,JVM 执行 .class 还需要 JRE 下的 lib 类库的支持,尤其是rt.jar。

    总结

    1. JRE 是运行时库,是提供给想运行 Java 程序的用户使用的;
    2. JDK 是开发工具包, 是提供给 Java 开发人员使用的;
    3. JDK包含了JRE, JRE包含了JVM。

     

    原文地址:https://blog.csdn.net/weixin_44259720/article/details/88634505

    展开全文
  • 什么是JVM虚拟机JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集...
  • 深入理解JVM虚拟机读书笔记——垃圾回收算法

    千次阅读 多人点赞 2021-08-25 10:52:49
    注:本文参考自周志明老师的著作《深入理解Java虚拟机(第3版)》 1. 如何判断对象已死? JVM 中判断对象是否已经死亡的算法主要有 2 种:引用计数法、可达性分析法。 1.1 引用计数法 如果一个对象被其他变量所...
  • 深入理解JVM虚拟机读书笔记——垃圾回收器

    千次阅读 多人点赞 2021-08-25 15:25:59
    注:本文参考自周志明老师的著作《深入理解Java虚拟机(第3版)》 如果说收集算法是内存回收的方法论,那垃圾收集器就是内存回收的实践者。《Java虚拟机规范》中对垃圾收集器应该如何实现并没有做出任何规定,因此...
  • 深入理解JVM虚拟机读书笔记——类的加载机制

    千次阅读 多人点赞 2021-08-25 17:59:28
    注:本文参考自周志明老师的著作《深入理解Java虚拟机(第3版)》 Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被称作...
  • 运行时数据区域image.png程序计数器当前线程执行字节码的行号指示器,通过改变程序计数器的值来选取...虚拟机虚拟机栈也是线程独有的,每个方法在执行的同时都会建立一个栈帧,用于储存局部变量表,操作数栈,动态链接...
  • 文章将同步到我的个人博客: www.how2playlife.com 本文是微信公众号【Java技术江湖】的《深入理解JVM虚拟机》其中一篇,本文部分内容来源于网络,为了把本文主题讲得清晰透彻,也整合了很多我认为不错的技术博客...
  • 深入理解JVM虚拟机 - 自我编译JDK 《深入理解JVM虚拟机》看过了好几遍了,对于编译一个JDK源码有很强的冲动。这里主要实战使用阿里云进行编译实战 为什么使用阿里云? 个人电脑奋斗四年了,装虚拟机莫名其妙的死机 ...
  • 深入理解JVM虚拟机读书笔记——锁优化

    千次阅读 多人点赞 2021-08-25 21:15:02
    注:本文参考自周志明老师的著作《深入理解Java虚拟机(第3版)》
  • 深入理解JVM虚拟机读书笔记——运行时数据区

    千次阅读 多人点赞 2021-08-22 19:55:58
    注:本文参考自周志明老师的著作《深入理解Java虚拟机(第3版)》 跨平台性是 Java 语言的重要特性,而这一特性本质上就是通过 JVM 虚拟机来实现的。下面就来通过深入学习 JVM 来进一步增加我们对 Java 这门编程...
  • 深入理解JVM虚拟机读书笔记——内存模型与线程

    千次阅读 多人点赞 2021-08-25 20:07:26
    注:本文参考自周志明老师的著作《深入理解Java虚拟机(第3版)》 1. Java内存模型 JMM概述: Java 内存模型指的是 JMM,而不是运行时数据区哦~ Java 语言为了保证并发编程中可以满足原子性、可见性及有序性,...
  • 本文转自互联网,侵删本系列文章将整理到我在...的《深入理解JVM虚拟机》其中一篇,本文部分内容来源于网络,为了把本文主题讲得清晰透彻,也整合了很多我认为不错的技术博客内容,引用其中了一些比较好的博客文章,...
  • 内容参考:《深入理解JVM虚拟机》 JVM 内存区域 程序计数器 是一块比较小的内存空间,可以看作是当前线程锁执行的字节码的行号指示器。 Java虚拟机的多线程是通过线程轮流切换,分配处理器执行时间来实现的,在任意...
  • Java虚拟机所管理的内存主要是如下几块五块区域 方法区、堆、虚拟机栈、本地方法栈、程序计数器 1.1、程序计数器 这个区域是唯一一个没有规定OutOfMemoryError 线程私有的,即每个线程都会创建一个自己的程序...
  • 最近在看周大大的《深入理解Java虚拟机JVM高级特性与最佳实践(第3版)》这本著作,准备编译个自己的JDK,刚开始是在自己的主力机win10上编译的。无奈针对Windows的坑点太多,故换成备用的MacBook Pro来编译。 .....
  • 一个类进行加载需要经过 加载,验证,准备,解析,初始化,使用,卸载几个步骤,接下来我们来讨论JVM在这中间做来哪些事情。 1. 加载 通过一个类的全限名来获取此类的二进制流 将这个字节流所代表的静态存储结构转化...
  • 深入理解JVM虚拟机 第二章 内存区域与内存溢出异常1. 概述2. 运行时数据区域2.1 程序计数器2.2 Java虚拟机栈2.3 本地方法栈2.4 Java堆2.5 方法区2.6 运行时常量池2.7 直接内存3. HotSpot 虚拟机对象探秘3.1 对象的...
  • 转自https://juejin.im/post/5abc97ff518825556a727e66所谓的「虚拟机字节码执行引擎」其实就是 JVM 根据 Class 文件中给出的字节码指令,基于栈解释器的一种执行机制。通俗点来说,也就是 JVM 解析字节码指令,输出...
  • 注:本文参考自周志明老师的著作《深入理解Java虚拟机(第3版)》 1. 对象的创建过程 在 Java 语言层面,创建对象一般是借助 new 关键字去实现: User user = new User(); 而在虚拟机中,对象的创建过程如下: ...
  • 第二章、内存区域与内存溢出异常 一、 java虚拟机运行时数据区: 程序计数器 一块较小内存空间,当前线程执行的字节码行号指示器。 由于Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的在...
  • 其实如果你经常解决服务器性能问题,那么这些问题就会变的非常常见,了解JVM内存也是为了服务器出现性能问题的时候可以快速的了解那块的内存区域出现问题,以便于快速的解决生产故障。 先看一张图,这张图能很清晰...
  • 在互联网公司里,有研发实力的大公司一般会选择自研或者基于开源组件进行二次开发,但是对于中小型公司来说直接选用一款开源软件会是一个不错的选择。 常用的注册与发现组件有eureka,zookeeper,consul,etcd等,...
  • Java与C++之间有一堵由内存动态分配与垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来——摘自《深入理解Java虚拟机》 1. 运行时数据区 Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存...
  • 在 Java内存运行时 区域的各个部分,其中 程序计数器、虚拟机栈、本地方法栈 三个区域随线程生灭,栈中的栈帧每个分配多少内存基本在类结构确定下来就已知的(虽然在编译期会被优化,但在概念模型的讨论中可以认为...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 58,832
精华内容 23,532
关键字:

深入理解jvm虚拟机

友情链接: degradados.zip