JVM基础


前言

JVM基础知识内容


提示:以下是本篇文章正文内容,下面案例可供参考

一、JVM位置

        JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

        引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

在这里插入图片描述

二、Java技术体系模块图

在这里插入图片描述

三、Java内存区域模型

在这里插入图片描述

1.方法区

        也称"永久代” 、“非堆”, 它用于存储虚拟机加载的类信息、常量、静态变量、是各个线程共享的内存区域。默认最小值为16MB,最大值为64MB,可以通过-XX:PermSize 和 -XX:MaxPermSize 参数限制方法区的大小。

        运行时常量池:是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种符号引用,这部分内容将在类加载后放到方法区的运行时常量池中。(简单的说:静态变量、常量、类信息(构造方法、接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆内存中,和方法区无关
注:方法区是一种特殊的堆

2.虚拟机栈

        描述的是java 方法执行的内存模型:每个方法被执行的时候都会创建一个“栈帧”用于存储局部变量表(包括参数)、操作栈、方法出口等信息。每个方法被调用到执行完的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。声明周期与线程相同,是线程私有的。

         局部变量表存放了编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(引用指针,并非对象本身),其中64位长度的long和double类型的数据会占用2个局部变量的空间,其余数据类型只占1个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量是完全确定的,在运行期间栈帧不会改变局部变量表的大小空间。(栈中不存在垃圾回收)

3.本地方法栈

        与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务。

4.堆

        也叫做java 堆、GC堆是java虚拟机所管理的内存中最大的一块内存区域,也是被各个线程共享的内存区域,在JVM启动时创建。该内存区域存放了对象实例及数组(所有new的对象)。其大小通过-Xms(最小值)和-Xmx(最大值)参数设置,-Xms为JVM启动时申请的最小内存,默认为操作系统物理内存的1/64但小于1G,-Xmx为JVM可申请的最大内存,默认为物理内存的1/4但小于1G,默认当空余堆内存小于40%时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRation=来指定这个比列;当空余堆内存大于70%时,JVM会减小heap的大小到-Xms指定的大小,可通过XX:MaxHeapFreeRation=来指定这个比列,对于运行系统,为避免在运行时频繁调整Heap的大小,通常-Xms与-Xmx的值设成一样。

        由于现在收集器都是采用分代收集算法,堆被划分为新生代和老年代。新生代主要存储新创建的对象和尚未进入老年代的对象。老年代存储经过多次新生代GC(Minor GC)任然存活的对象。

新生代:
         序新创建的对象都是从新生代分配内存,新生代由Eden Space和两块相同大小的Survivor Space(通常又称S0和S1或From和To)构成,可通过-Xmn参数来指定新生代的大小,也可以通过-XX:SurvivorRation来调整Eden Space及Survivor Space的大小。

老年代:
        用于存放经过多次新生代GC任然存活的对象,例如缓存对象,新建的对象也有可能直接进入老年代,主要有两种情况:①.大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配。②.大的数组对象,切数组中无引用外部对象。

        老年代所占的内存大小为-Xmx对应的值减去-Xmn对应的值。
在这里插入图片描述
永久区(Perm)(JDK8以后叫元空间):
        JVM系统信息或者用不需要回收的数据,属于堆,为了与Heap区别,经常会叫非堆。方法区就存储在该位置.。元空间逻辑上存在,但是物理上不存在

注:GC回收主要集中在伊甸园区和老年区进行。当新生区中伊甸园区满了,会触发伊甸园区移到幸存区S0,S!,当新生区中伊甸园区、幸存区(S0,S1)满了,会触发重GC,会将新生区和老年区进行清理,并把新生区活下来的移到老年区。

OOM解决方法:
        1.尝试扩大堆内存看结果
        2.分析内存,看一下哪个地方出现了问题

5.程序计数器

         是最小的一块内存区域,它的作用是当前线程所执行的字节码的行号指示器,在虚拟机的模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、异常处理、线程恢复等基础功能都需要依赖计数器完成。

6.直接内存

         直接内存并不是虚拟机内存的一部分,也不是Java虚拟机规范中定义的内存区域。jdk1.4中新加入的NIO,引入了通道与缓冲区的IO方式,它可以调用Native方法直接分配堆外内存,这个堆外内存就是本机内存,不会影响到堆内存的大小。

7.小结

        方法区是特殊的堆,垃圾存在在堆中,JVM调优主要是针对堆进行调优

四、类加载器

在这里插入图片描述

1.JVM和类

        当我们调用Java命令运行某个Java程序时,该命令将会启动一个Java虚拟机进程,不管该Java程序有多么复杂,该程序启动了多少个线程,它们都会处于该Java虚拟机进程里。正如前面介绍的,同一个JVM的所有线程、所有变量都处于同一个进程里,它们都使用该JVM进程的内存区。当系统出现以下几个情况时,JVM进程将被终止。

        1.程序运行到最后正常结束。
        2.程序运行到使用System.exit()或Runtime.getRuntime().exit()代码处结束程序。
        3.程序执行过程中遇到未捕获的异常或错误而结束。
        4.程序所在平台强制结束了JVM进程。

2.类的生命周期

在这里插入图片描述

3.类的加载

        当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化3个步骤来对该类进行初始化。如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化。

        类加载指的是将类的class文件读入到内存,并为之创建一个java.lang.Class对象,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。也就是说,当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

        类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础,JVM提供的这些类加载器通常被称为系统类加载器。除此之外,开发者可以通过继承ClassLoader基类来创建自己的类加载器。(JVM相关知识等我看完《深入理解Java虚拟机》再写,这些现在也是没怎么理解)

        通过使用不同的类加载器,可以从不同来源加载类的二进制数据,通常有如下几种来源。

  • 从本地文件系统加载class文件,这是前面绝大部分示例程序的类加载方式。
  • 从JAR包加载class文件,这种方式也是很常见的,前面介绍JDBC编程时用到的数据库驱动类就放
  • 在JAR文件中,JVM可以从JAR文件中直接加载该class文件。
  • 通过网络加载class文件。 把一个Java源文件动态编译,并执行加载。

        类加载器通常无须等到“首次使用”该类时才加载该类,Java虚拟机规范允许系统预先加载某些类。

4.类的连接

        当类被加载之后,系统为之生成一个对应的Class对象,接着将会进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中。类连接又可分为如下3个阶段。
          1、 验证:验证阶段用于检验被加载的类是否有正确的内部结构,并和其他类协调一致。
          2、 准备:类准备阶段负责为类的静态变量分配内存,并设置默认初始值。
          3、 解析:将类的二进制数据中的符号引用替换成直接引用。

5.类的初始化

        在类的初始化阶段,虚拟机负责对类进行初始化,主要就是对静态Field进行初始化。在Java类中对静态变量指定初始值有两种方式:
          1、声明静态变量时指定初始值。
          2、使用静态初始化块为静态变量指定初始值。
  JVM初始化一个类包含如下几个步骤。
          1、 假设这个类还没有被加载和连接,则程序先加载并连接该类。
          2、 假设该类的直接父类还没有被初始化,则先初始化其直接父类。
          3、 假设类中有初始化语句,则系统依次执行这些初始化语句。
        当执行第2个步骤时,系统对直接父类的初始化步骤也遵循此步骤1-3;如果该直接父类又有直接父类,则熊再次重复这3个步骤来先初始化这个父类。。。依次类推,所以JVM最先初始化的总是java.lang.Object类。当程序主动使用任何一个类时,系统会保证该类以及所有父类都会被初始化。

6.类初始化的时机

        当Java程序首次通过下面6种方式来使用某个类或接口时,系统就会初始化该类或接口。

        1. 创建类的实例对象。为某个类创建实例对象的方式包括:使用new操作符来创建实例对象,通过反射来创建实例对象,通过反序列化的方式来创建对象。
        2.调用某个类的静态方法。
        3. 访问某个类或接口的静态变量,或为该静态变量赋值。
        4. 使用反射方式来强制创建某各类或接口对应的java.lang.Class对象。例如代码:Class.forName(“Person”),如果系统还未初始化Person类,则这行代码将会导致该Person类被初始化,并返回Person类对应的java.lang.Class对象。
        5. 创建某个子类的实例对象。当初始化某个类的子类的实例对象时,该子类的所有父类都会被初始化。
        6. 直接使用java.exe命令来运行某个主类。当运行某个主类时,程序会先初始化该类。
        除此之外,下面几种情形需要特别指出。
        对于一个final类型的静态变量,如果该变量的值在编译时就可以确定下来,那么这个变量相当于“宏变量”。Java编译器会在编译时直接把这个变量出现的地方替换成它的值,因此即使程序使用该静态变量,也不会导致该类的初始化。

7.类加载

        类加载器负责将.class文件(可能在磁盘上,可能在网络上)加载到内存中,并为之生成对应的java.lang.Class对象。(虽然开发中不用咱写)
        类加载器负责加载所有的类,系统为所有被载入内存中的类生成一个java.lang.Class实例对象。一旦一个类被加载如JVM中,同一个类就不会被再次载入了。现在的问题是,怎么样才算“同一个类”?
        正如一个对象有一个唯一的标识一样,一个载入JVM的类也有一个唯一的标识。在Java中,一个类用其全限定类名(包括包名和类名)作为标识;但在JVM中,一个类用其全限定类名和其类加载器作为其唯一标识。例如,如果在pg的包中有一个名为Person的类,被类加载器ClassLoader的实例kl负责加载,则该Person类对应的Class对象在JVM中表示为(Person、pg、kl)。这意味着两个类加载器加载的同名类:(Person、pg、kl)和(Person、pg、kl2)是不同的、它们所加载的类也是完全不同、互不兼容的。
        Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。系统提供的类加载器主要有下面三个:
        1.引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader 。
        2.扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
        3.系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader() 来获取它。
        除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader 类的方式实现自己的类加载器,以满足一些特殊的需求。
        Bootstrap ClassLoader被称为引导类加载器,它负责加载Java的核心类。在Sun的JVM中当执行java.exe命令时,使用-Xbootclasspath选项或使用-D选项指定sun.boot.class.path系统属性值可以指定加载附加的类。

在这里插入图片描述         ExtClassLoader和AppClassLoader都是ClassLoader的子类

8.类加载机制

        JVM的类加载机制主要有如下3种。

        1.全盘负责:所谓全盘负责,就是当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。
        2.父类委托:所谓的父类委托,则是先让parent类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。
        3.缓存机制:缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为很么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。
        除了可以使用Java提供的类加载器之外,开发者也可以实现自己的类加载器,自定义的类加载器通过继承ClassLoader来实现。

        类加载器加载Class大致要经过如下8个步骤:
        1、 检测此Class是否载入过,即在缓冲区中是否有此Class,如果有直接进入第8步,否则进入第2步。
        2、 如果没有父类加载器,则要么Parent是根类加载器,要么本身就是根类加载器,则跳到第4步,如果父类加载器存在,则进入第3步。
        3、 请求使用父类加载器去载入目标类,如果载入成功则跳至第8步,否则接着执行第5步。
        4、 请求使用根类加载器去载入目标类,如果载入成功则跳至第8步,否则跳至第7步。
        5、 当前类加载器尝试寻找Class文件,如果找到则执行第6步,如果找不到则执行第7步。
        6、 从文件中载入Class,成功后跳至第8步。
        7、 抛出ClassNotFountException异常。
        8、 返回对应的java.lang.Class对象。
        其中,第5、6步允许重写ClassLoader的findClass()方法来实现自己的载入策略,甚至重写loadClass()方法来实现自己的载入过程。

9.类的卸载

        当类被加载、连接和初始化后,它的生命周期就开始了。
        当类的Class对象不再被引用,即不可触及时,Class对象就会结束生命周期,类在方法区内的数据也会被卸载,从而结束类的生命周期。
        由此可见,一个类何时结束生命周期,取决于代表它的Class对象何时结束生命周期。
引用关系
  加载器和Class对象:
           在类加载器的内部实现中,用一个Java集合来存放所加载类的引用。
           另一方面,一个Class对象总是会引用它的类加载器。调用Class对象的getClassLoader()方法,就能获得它的类加载器。
           由此可见,Class实例和加载它的加载器之间为双向关联关系
   类、类的Class对象、类的实例对象:
           一个类的实例总是引用代表这个类的Class对象。
           在Object类中定义了getClass()方法,这个方法返回代表对象所属类的Class对象的引用
           此外,所有的Java类都有一个静态属性class,它引用代表这个类的Class对象。

类的卸载
        由Java虚拟机自带的类加载器所加载的类,在虚拟机的生命周期中,始终不会被卸载。前面介绍过,Java虚拟机自带的类加载器包括根类加载器、扩展类加载器和系统类加载器。
        Java虚拟机本身会始终引用这些类加载器,而这些类加载器则会始终引用它们所加载的类的Class对象,因此这些Class对象始终是可触及的。
        由用户自定义的类加载器加载的类是可以被卸载的。
【总结】
        (1) 启动类加载器加载的类型在整个运行期间是不可能被卸载的(jvm和jls规范);
        (2) 被系统类加载器和标准扩展类加载器加载的类型在运行期间不太可能被卸载,因为系统类加载器实例或者标准扩展类的实例基本上在整个运行期间总能直接或者间接的访问的到,其达到unreachable的可能性极小。(当然,在虚拟机快退出的时候可以,因为不管ClassLoader实例或者Class(java.lang.Class)实例也都是在堆中存在,同样遵循垃圾收集的规则);
        (3) 被开发者自定义的类加载器实例加载的类型只有在很简单的上下文环境中才能被卸载,而且一般还要借助于强制调用虚拟机的垃圾收集功能才可以做到.可以预想,稍微复杂点的应用场景中(尤其很多时候,用户在开发自定义类加载器实例的时候采用缓存的策略以提高系统性能),被加载的类型在运行期间也是几乎不太可能被卸载的(至少卸载的时间是不确定的)
        综合以上三点, 一个已经加载的类型被卸载的几率很小至少被卸载的时间是不确定的。同时我们可以看的出来,开发者在开发代码时候,不应该对虚拟机的类型卸载做任何假设的前提下来实现系统中的特定功能。
        类加载机制避免了类的冲突,保证安全

五、安全模型–沙箱安全机制

相关介绍:
   我们都知道,程序员编写一个Java程序,默认的情况下可以访问该机器的任意资源,比如读取,删除一些文件或者网络操作等。当你把程序部署到正式的服务器上,系统管理员要为服务器的安全承担责任,那么他可能不敢确定你的程序会不会访问不该访问的资源,为了消除潜在的安全隐患,他可能有两种办法:

        1.让你的程序在一个限定权限的帐号下运行。
        2.利用Java的沙箱机制来限定你的程序不能为非作歹。以下用于介绍该机制。

1.什么是沙箱

        Java安全模型的核心就是Java沙箱(sandbox),什么是沙箱?沙箱是一个限制程序运行的环境。沙箱机制就是将 Java 代码限定在虚拟机(JVM)特定的运行范围中,并且严格限制代码对本地系统资源访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏。沙箱主要限制系统资源访问,那系统资源包括什么?——CPU、内存、文件系统、网络。不同级别的沙箱对这些资源访问的限制也可以不一样。
所有的Java程序运行都可以指定沙箱,可以定制安全策略。

java中的安全模型:
        在Java中将执行程序分成本地代码和远程代码两种,本地代码默认视为可信任的,而远程代码则被看作是不受信的。对于授信的本地代码,可以访问一切本地资源。而对于非授信的远程代码在早期的Java实现中,安全依赖于沙箱 (Sandbox) 机制。如下图所示
在这里插入图片描述
JDK1.1安全模型

        在 Java1.2 版本中,再次改进了安全机制,增加了代码签名。不论本地代码或是远程代码,都会按照用户的安全策略设定,由类加载器加载到虚拟机中权限不同的运行空间,来实现差异化的代码执行权限控制。针对安全机制做了改进, 增加了安全策略,允许用户指定代码对本地资源的访问权限。如下图所示
在这里插入图片描述
JDK1.2安全模型

        当前最新的安全机制实现,则引入了域 (Domain) 的概念。虚拟机会把所有代码加载到不同的系统域和应用域,系统域部分专门负责与关键资源进行交互,而各个应用域部分则通过系统域的部分代理来对各种需要的资源进行访问。虚拟机中不同的受保护域 (Protected Domain),对应不一样的权限 (Permission)。再次改进了安全机制, 增加了代码签名。不论本地代码或是远程代码,都会按照用户的安全策略设定,由类加载器加载到虚拟机中权限不同的运行空间,来实现差异化的代码执行权限控制。存在于不同域中的类文件就具有了当前域的全部权限,如下图所示
在这里插入图片描述
JDK1.6安全模型

        当前最新的安全机制实现,则引入了域 (Domain) 的概念。虚拟机会把所有代码加载到不同的系统域和应用域,系统域部分专门负责与关键资源进行交互,而各个应用域部分则通过系统域的部分代理来对各种需要的资源进行访问。虚拟机中不同的受保护域 (Protected Domain),对应不一样的权限 (Permission)。存在于不同域中的类文件就具有了当前域的全部权限,如下图所示 最新的安全模型(jdk 1.6)
在这里插入图片描述
        以上提到的都是基本的Java 安全模型概念,在应用开发中还有一些关于安全的复杂用法,其中最常用到的 API 就是 doPrivileged。doPrivileged 方法能够使一段受信任代码获得更大的权限,甚至比调用它的应用程序还要多,可做到临时访问更多的资源。有时候这是非常必要的,可以应付一些特殊的应用场景。例如,应用程序可能无法直接访问某些系统资源,但这样的应用程序必须得到这些资源才能够完成功能。

2.组成沙箱的基本组件:

         字节码校验器(bytecode verifier):确保Java类文件遵循Java语言规范。这样可以帮助Java程序实现内存保护。但并不是所有的类文件都会经过字节码校验,比如核心类。
         类装载器(class loader):其中类装载器在3个方面对Java沙箱起作用
        1.它防止恶意代码去干涉善意的代码;
        2.它守护了被信任的类库边界;
        3.它将代码归入保护域,确定了代码可以进行哪些操作。
虚拟机为不同的类加载器载入的类提供不同的命名空间,命名空间由一系列唯一的名称组成,每一个被装载的类将有一个名字,这个命名空间是由Java虚拟机为每一个类装载器维护的,它们互相之间甚至不可见。

        类装载器采用的机制是双亲委派模式。

        1.从最内层JVM自带类加载器开始加载,外层恶意同名类得不到加载从而无法使用;
        2.由于严格通过包来区分了访问域,外层恶意的类通过内置代码也无法获得权限访问到内层类,破坏代码就自然无法生效。
存取控制器(access controller):存取控制器可以控制核心API对操作系统的存取权限,而这个控制的策略设定,可以由用户指定。
安全管理器(security manager):是核心API和操作系统之间的主要接口。实现权限控制,比存取控制器优先级高。
安全软件包(security package):java.security下的类和扩展包下的类,允许用户为自己的应用增加新的安全特性,包括:
        安全提供者
        消息摘要
        数字签名
        加密
        鉴别

六、Native(即JNI,Java Native Interface)

1. JNI简介

        native方法是通过java中的JNI实现的。JNI是Java Native Interface的 缩写。从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。 JNI一开始是为了本地已编译语言,尤其是C和C++而设计 的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下。
         目前java与dll交互的技术主要有3种:jni,jawin和jacob。Jni(Java Native Interface)是sun提供的java与系统中的原生方法交互的技术(在windows\linux系统中,实现java与native method互调)。目前只能由c/c++实现。后两个都是sourceforge上的开源项目,同时也都是基于jni技术的windows系统上的一个应用库。Jacob(Java-Com Bridge)提供了java程序调用microsoft的com对象中的方法的能力。而除了com对象外,jawin(Java/Win32 integration project)还可以win32-dll动态链接库中的方法。就功能而言:jni >> jawin>jacob,其大致的结构如下图:
在这里插入图片描述
         就易用性而言,正好相反:jacob>jawin>>jni。
        Jvm封装了各种操作系统实际的差异性的同时,提供了jni技术,使得开发者可以通过java程序(代码)调用到操作系统相关的技术实现的库函数,从而与其他技术和系统交互,使用其他技术实现的系统的功能;同时其他技术和系统也可以通过jni提供的相应原生接口开调用java应用系统内部实现的功能。

        在windows系统上,一般可执行的应用程序都是基于native的PE结构,windows上的jvm也是基于native结构实现的。Java应用体系都是构建于jvm之上。
在这里插入图片描述
        Jni对于应用本身来说,可以看做一个代理模式。对于开发者来说,需要使用c/c++来实现一个代理程序(jni程序)来实际操作目标原生函数,java程序中则是jvm通过加载并调用此jni程序来间接地调用目标原生函数。
在这里插入图片描述
JNI的书写步骤:
        1.编写带有native声明的方法的java类,生成.java文件
        2.使用javac命令编译所编写的java类,生成.class文件
        3.使用javah -jni java类名生成扩展名为h的头文件,也即生成.h文件
        4.使用C/C++(或者其他编程想语言)实现本地方法,创建.h文件的实现,也就是创建.cpp文件实现.h文件中的方法
        5.将C/C++编写的文件生成动态连接库,生成dll文件

2. JNI基本原理

        方法中带有native的关键字说明Java的作用范围打不到了,回去调用底层C语言的库,会进入本地方方法栈。调用原理如下图所示:
在这里插入图片描述
        native方法在内存区域中专门开辟了 一块标记区域:Native Method Stack,登记Native方法,在最终执行的时候,加载本地方法库中的方法通过JNI进行调用

3. JNI作用

        扩展Java的使用,融合不同的编程语言为Java所用。最初是C,C++


总结

JVM基础知识,但是缺少GC算法整理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拥有必珍惜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值