了解JVM,不仅是在面试时增加几率,更是在开发过程进行优化调整时了解内存溢出等,因此需要知道这个是什么东东,有什么卵用?

  朋友,看20分钟的呗,了解下?(有木有发传单的赶脚?嘻嘻~~)

  正好前段时间看了《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》这本书,而且在腾讯课堂听了某位大大的讲解,所以本篇记录下,一是自己了解并笔记,二能帮助他人就更好了。(就是下面这本书...看的自己有点怀疑人生...)

  

  java发展?

    学习java的朋友都清楚java的特性,”write Once,Run Anywhere”,而支持其此特性最大的一点就是java虚拟机(JVM)。

    1.  从1996年 Sun 公司发布JDK1.0时,其中内置的虚拟机是Classic VM,它是第一款商用的虚拟机,这款虚拟机只能使用纯解释器方式来执行java代码,每一方法,每一行代码都必须进行编译,编译耗时非常高,这就造成了业界对Java语言运行很慢的印象。但是其可以使用外挂JIT编译器(Just In Time),但此时的即时编译与纯解释编译不可以同时工作。

    2.  1998年,JDK1.2版本中的虚拟机是Exact VM,经过java团队的优化,采用精准式的内存管理,其执行系统已经具备现代高性能虚拟机的雏形,如:两级即时编译器、编译器与解释器混合工作模式等。

    PS:《深入理解java虚拟机》一书中提及,JDK1.2中曾并存过三种虚拟机,Classic VM、Exact VM、Hotspot VM

        Classic VM只能以外挂的形式使用JIT编译器,Exact VM、Hotspot VM内置了JIT编译器。

    3.  1999年,Hotspot VM发布,实质上该虚拟机是由名为“Longview Technologies”的小公司设计的,由于其优异表现于1997年被Sun公司收购,Hotspot VM发布时是作为JDK1.2的附加程序提供的,但其后来成为了JDK1.3及以后的其他版本的默认虚拟机。

    PS:HotSpot VM如其名称,热点代码探测能力,一开始就是准确式GC(Garbar Collection)。

       如果一个方法被频繁调用,或方法中有效循环次数很多,将会分别触发标准编译和OSR(栈上替换)编译动作。通过编译器与解释器恰当地协同工作,可以在最优化的程序响应时间与最佳执行性能中取得平衡,而且无须等待本地代码输出才能执行程序,即时编译的时间压力也相对减小,这样有助于引入更多的代码优化技术,输出质量更高的本地代码。

    4.  自JDK 1.3始,Sun公司维持一个习惯,每隔两年发布一个JDK版本,以动物命名,期间发布的修正版本则以昆虫为工程名称。

    5.  大事发生了!!!2008年和2009年,Oracle公司分别收购了BEA公司和Sun公司,这样Oracle就同时拥有了两款优秀的Java虚拟机:JRockit VM和HotSpot VM。Oracle公司宣布在不久的将来(大约应在发布JDK 8的时候)会完成这两款虚拟机的整合工作,使之优势互补。整合的方式大致上是在HotSpot的基础上,移植JRockit的优秀特性,譬如使用JRockit的垃圾回收器与MissionControl服务,使用HotSpot的JIT编译器与混合的运行时系统。

    6. 2014年,Oracle发布了JDK1.8,此版本是JDK近几年的稳定版本,也是自JDK1.5以来改动最大的一个版本,各公司一直在用该版本。

    7. 2017年、2018年分别发布了Java9、Java10,这两个版本属短期版本,本博主已处在跟不上的阶段了,而且上个版本还没完全熟悉...惆怅...

    

  java虚拟机发展?

    可以参考本篇:https://201610042321.iteye.com/blog/2337901

    1.Sun 公司  ---   Classic VM、Exact VM、Hotpost VM、KVM、Squawk VM、Maxine VM...

    2.BEA公司   ---  JRockit VM

    3.IBM公司    ---  J9 VM、K8 VM

    4.还有Apache Harmoney、Google Android Dalvik VM、Microsoft JVM等等好多的虚拟机...

  JVM是什么?

    如上图:

      JDK:Java Development Kit,是整个java的核心,包含了JRE,Java开发工具,Java编译器等;

      JRE:Java Runtime Enviromennt,运行Java程序的必须环境,包含JVM与java程序需要的核心类库;

      JVM:Java Virtual Machine,是Java实现跨平台的最核心部分,将字节码文件转换为系统机器指令,并解释执行,JVM是运行在操作系统之上的,没有直接与硬件交互。

   Java源程序编译为字节码文件?

     日常编程的文件都是 *.java文件,而在JVM中运行的文件则需要是 *.class文件,这其中的过程是如何进行编译的呢?

    其中具体的编译过程可以阅读【龙书】《编译原理》,这本书里面讲解了程序是如何进行编译的,是非常牛掰的一本著作。

    亦可参考这两篇:https://www.jianshu.com/p/b9d3f20a880e

            http://m.elecfans.com/article/668346.html

            https://blog.csdn.net/wy727764020/article/details/80411751

    编译是将一种抽象程度更高的语言转换为更贴近计算机能够识别的语言的过程。

    Java属高级语言,一是其更贴近人类语言,更易理解(语法);二是平台无关性,无需兼容不同系统(跨平台);三是无需管理内存,更关注业务实现(内存管理)。

    通常命令行窗口在对应的目录下执行javac *.java命令,编译成功会在当前目录下生成对应的class字节码文件,执行java *得到执行后结果。

    java代码执行过程:Java源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行。

    通用代码编译器的步骤:

    Java代码编译器的步骤:

 

      实质上,JVM在JIT编译阶段就做了相关的优化,如逃逸分析、 锁消除、 锁膨胀、 方法内联、 空值检查消除、 类型检测消除、 公共子表达式消除等等。

    有兴趣的朋友可以搜索一下,顺便了解一下此处相关的具体优化点。

  

  JVM加载class文件?

    加载,实质上是将字节码(类的二进制字节流)文件由磁盘读取至虚拟机内存中,再通过类加载器完成,整个过程包含了7个阶段:

    具体过程是按以上顺序开始的,但不是按顺序进行完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。

    

    装载

      该阶段需要完成以下3步操作:

        1.通过ClassLoader在classPath中获取*.class文件,将其以二进制流形式读入JVM内存中;

        2.将此字节流代表的静态存储结构转换为方法区中的运行时数据结构;

        3.在(堆)内存中,生成代表该类的Class对象,作为对方法区中的数据访问入口。

      装载阶段是可控性最强的阶段,开发人员可以使用系统的类加载器,也可使用自定义的类加载器来完成此阶段(继承ClassLoader)。

      类加载器分为3大类:

        1.启动类加载器:Bootstrap ClassLoader,是虚拟机的一部分,负责加载JDK/jre/lib下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的java.*开头的类均被Bootstrap ClassLoader加载)。启动类加载器是无法被Java程序直接引用的。

        2.扩展类加载器:Extension ClassLoader,该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载JDK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器。
        3.应用程序类加载器:Application ClassLoader,该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
  

      这三种类加载器的关系如下图,这几者之间的关系并非继承,而是组合的关系。

      关于加载时,JVM的加载机制有3种:

        1.全盘负责:加载某一class时,会将其相关的其他class也由该类加载器负责加载;

        2.双亲委派:先告知其父类,父类再告知其祖类,直至最顶层类加载器,最顶层加载成功,则返回,否则依次向下进行加载,若都没有,则抛ClassNotFoundError;

        3.缓存机制:宝成所有加载过的class都被缓存,当程序中使用某个class时,类加载器会先从缓存中寻找该class,若不存在,则读取该类二进制文件,转换为class对象后,再次放入缓存区,若修改了class,则不需重启JVM,修改才会再次生效。

      java虚拟机采用的加载机制是 - 双亲委派模型

      采用该机制的优点是 - 采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载

      提问:按照上述解释,JVM明明是父类委派或者是单亲委派,但为什么一直称为’双亲委派’呢???

    验证

      主要是确保class文件的字节流符合JVM规范,且不会危害虚拟机自身的安全。主要包括四种验证:文件格式验证,元数据验证,字节码验证,符号引用验证。

      对虚拟机自身安全的一种保证机制,保证应用是否会被恶意入侵的一道重要的防线,越是严谨的验证机制越安全。

    准备

      为类的静态变量分配内存,并设置默认初始值,这些内存都将在方法区中存在。

    解析

      虚拟机将常量池内的符号引用替换为直接引用的过程, 解析动作主要针对类或接口、字段、类方法、接口方法四类符号引用进行。

      符号引用:以一组符号来描述所引用的目标。符号引用可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可,符号引用和虚拟机的布局无关。
      直接引用:可以是指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄,直接引用和虚拟机的布局是相关的,如果有了直接引用,那么直接引用的目标一定被加载到了内存中。

    初始化

      真正开始执行类中定义的Java程序代码,主要是根据程序中的赋值语句主动为类变量赋指定值。

    执行

      程序中方法之间的相互调用。

    卸载

      销毁一个对象,一般情况下中有JVM垃圾回收器完成。代码层面的销毁只是将引用置为null。

    整个类加载过程中,除了在装载阶段,可使用自定义的类加载器参与外,其余阶段全部都由虚拟机主导控制,在初始化阶段才真正执行字节码文件,

    若你能看到此处,那接下来的东西才是真正的JVM的区域划分介绍。  -.-

  JVM运行时数据区域划分?

     在介绍JVM数据区域划分时,先简单的运行一个简单地代码,便于分析java文件 -> class文件 在 JVM之中的存在及执行关系。

    先用一个test来查看一下源文件编译后的class文件之间的对应关系吧,如下图:这种的二进制文件,反正本人(想起来不良人中的本人了)是看的费劲,能理解一点点的一点点...

    将左边的 Test.java 进行 javac Test.java 编译后,生成右边的 Test.class 字节码文件,如果需要进行查看,需要使用 javap -v Test.class 反解析字节码文件,生成可看懂的文件。

    

    关于Javap命令反编译后的文件具体信息可以参考:https://www.jianshu.com/p/6a8997560b05

   

    当反编译之后的字节码文件,可以参考JVM字节码指令进行查询相应的跳转处理逻辑,其中关于锁,i++ / ++i 等等操作原理都可以剖析下,上面的反编译代码至截取了当中的 main() 和 addAndTest() 这两个方法,其他的类元信息、主次版本号、常量信息,属性信息等都没有截取,有兴趣的朋友可以自己试一下,参照JVM指令查看一下反编译后的文件。

    大家看到反编译后的文件中有bipush、astore_1、aload_1等等指令,这些都是在JVM中进行操作的,该代码是引出接下来的JVM模型的....

    看到这儿的朋友,10分钟应该是过去了,也就是喝杯水休息的功夫,不过注意了,因为接下来就要变形了,呃,不对,是真正的JVM模型的讲解了。

    先看一张JVM的本身内存结构图,如下:

    (画了好一会儿呐)可以参考下这篇博文,讲解的还是非常清楚的:https://www.nowcoder.com/discuss/151138?type=1

    线程计数器:

      程序计数器是一块较小的内存空间,可看作当前线程正在执行的字节码的行号指示器。若当前线程正在执行的是Java方法,计数器记录的就是当前线程正在执行的字节码指令的地址(行号);若是本地Native方法,那么程序计数器值为undefined

      程序计数器有两个作用:字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理;在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被来回切换时清楚该线程运行位置,即线程切换后能恢复到正确的执行位置。

      线程私有。每条线程都有一个独立的程序计数器,而且是JVM中唯一一个不会出现OOM的内存区域。生命周期随着线程的创建而创建,随着线程的结束而死亡。

      思考:线程计数器指的是当前线程的字节码行号指示器,那为什么可以根据它来选取下一条需要执行的字节码指令?

       答:记录当前线程所执行的字节码行号,用于获取下一条执行的字节码。在每次指令执行后自增, 维护下一个将要执行指令的地址,若当前为最后的行号,则其会根据最后的return语句进入下一个要执行的线程位置,再获取当前线程此位置的行号。

    Java 栈:

        虚拟机栈描述的是Java方法执行的内存区域,也是线程私有的: 每个方法被执行时会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
      栈中的元素用于支持虚拟机进行方法调用,每个方法从开始调用到执行完成的过程,就是栈帧在虚拟机栈中从入栈到出栈的过程
      在活动线程中,只有位于栈顶的帧才是有效的,称为当前栈帧,在执行引擎运行时,所有指令都只能针对当前栈帧进行操作;正在执行的方法称为当前方法;栈帧是方法运行的基本结构,其压栈弹栈方式是FILO(First In Last Out)。

      关于运行时的栈帧结构,可以参考一下这篇博文:https://www.cnblogs.com/wade-luffy/p/6058067.html

      Java虚拟机栈会出现两种异常:
        StackOverFlowError:若Java虚拟机栈的内存大小不允许动态扩展,那么当线程请求的栈深度大于虚拟机允许的最大深度时(但内存空间可能还有很多),就抛出此异常;
        OutOfMemoryError:若Java虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError异常;
      Java虚拟机栈也是线程私有的,每个线程都有各自的Java虚拟机栈,而且随着线程的创建而创建,随着线程的死亡而死亡。

    本地方法栈:

      本地方法栈与虚拟机栈所发挥的作用是非常相似的,其区别不过是Java虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常

      该区域也是线程私有的,对JVM而言,java虚拟机栈“主内”,而本地方法栈“主外”,本地方法可以通过JNI(Java Native Interface)来访问虚拟机运行时的数据区,甚至可以调用寄存器,具有和JVM相同的能力和权限,当大量本地方法出现时,势必会削弱JVM对系统的控制力,大量使用其他语言来实现JNI,就会丧失跨平台特性,威胁到程序运行的稳定性,因为它的出错信息都比较黑盒。

    java 堆:

      Java虚拟机所管理的内存中最大且被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。

      Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”(Garbage Collected Heap)。从内存回收的角度来看,由于现在收集器基本都采用分代收集算法,所以Java堆还可以细分为:新生代和老年代;新生代又可以分为:Eden 空间、From Survivor空间、To Survivor空间。如果从内存分配的角度看,线程共享的Java 堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。在实现时,既可以实现成固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的(通过-Xms和-Xmx控制)。如果在堆中没有内存完成实例的分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

      此处关于堆的空间就少介绍一点吧,等到后面再开一篇博客详细讲解关于堆中的具体信息,本篇主要关注的是堆中的东西。也就是对象在堆中是如何存在的?

      那对象是如何创建的呢?如下图:

      在HotspotVM中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

        1.对象头

          第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,官方称之为MarkWord;


          另外一部分是类型指针,即对象指向它的类元数据的指针, 虚拟机通过这个指针来确定这个对象是哪个类的实例实例数据。

        2.实例数据

          对象真正存储的有效信息,也是在程序代码中所定义的各种 类型的字段内容。 无论是从父类继承下来的,还是在子类中 定义的,都需要记录起来对齐填充。

        3.对齐填充

          非必要存在, 仅起到占位符的作用, 原因是HotSpot自动内存管理系统要求对象起始地址必须是8字节的整数倍, 即对象的大小必须是8字节的整数倍.

      对象的访问定位:

        JVM 规范中并没有详细规定引用类型的实现细节,比如引用应该通过何种方式去定位、访问堆中的对象,具体的对象访问方式取决于虚拟机的具体实现,比如 HotSpot 有其自己的实现方案。目前主流的访问方式有使用句柄和直接指针两种,如下图:

    方法区:非堆 / 永久代

      方法区是堆空间的一个外延部分,但并非属于堆,因此还可称其为 ' Non-Heap(非堆) ',方法区中存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

      方法区中的信息一般需要长期存在,而且它又是堆的逻辑分区,因此用堆的划分方法,我们把方法区称为‘ 永久代 (Permanent Generation)’。这部分空间大小可扩展,其中数据是线程共享的。

       HotSpot VM虚拟机把GC分代收集扩展至方法区, 即使用Java堆的永久代来实现方法区,这样HotSpot的垃圾收集器就可以像管理Java堆一样管理这部分内存, 而不必为方法区开发专门的内存管理器(永久带的内存回收的主要目标是针对常量池的回收和类型的卸载, 因此收益一般很小)。只有Hotspot才有Perm区(永久代),它在启动时固定大小,很难进行调优,并且Full GC时会移动类元信息。而对于其他虚拟机(如BEA JRockit、IBM J9 等)来说是不存在永久代的概念的。

        运行时常量池:

          运行时常量池是方法区的一部分。其中方法区中的常量存储在运行时常量池中

          常量池( Constant pool table)中存放编译时期产生的各种字面量和符号引用,.class文件中的常量池中的所有的内容在类被加载后存放到方法区的运行时常量池中。运行时常量池相对于class文件常量池的另外一个特性是具备动态性,java语言并不要求常量一定只有编译器才产生,也就是并非预置入class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中。如String类中的intern()方法就是采用了运行时常量池的动态性。当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串,则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用,就是在运行期间向常量池中添加字符串常量

          在近三个JDK版本(6、7、8)中, 运行时常量池的所处区域一直在不断的变化,在JDK6时它是方法区的一部分,7又把他放到了堆内存中,8之后出现了元空间,它又回到了元空间

          运行时常量池是方法区的一部分,所以会受到方法区内存的限制,因此当常量池无法再申请到内存时就会抛出OutOfMemoryError异常。当运行时常量池中的某些常量没有被对象引用,同时也没有被变量引用,那么就需要垃圾收集器回收

    元空间:JDK1.8之后代替方法区的区域。

      在JDK8之后,永久代被移除,原本存储在永久代的数据将存放在一个叫做元空间(Metaspace)的本地内存区域

      在Java虚拟机(以下简称JVM)中,类包含其对应的元数据,比如类的层级信息,方法数据和方法信息(如字节码,栈和变量大小),运行时常量池,已确定的符号引用和虚方法表。在过去(当自定义类加载器使用不普遍的时候),类几乎是“静态的”并且很少被卸载和回收,因此类也可以被看成“永久的”。另外由于类作为JVM实现的一部分,它们不由程序来创建,因为它们也被认为是“非堆”的内存。

      如果在JDK8之前碰到java.lang.OutOfMemoryError: PermGenspace,为解决该问题,需要设置永久代的运行参数:-XX:MaxPermSize= l280m。若将此部署到新机器上,也需要再次调参数信息,所以在JDK8中使用元空间替换永久代。区别于永久代,元空间在本地内存中分配,即:只要本地内存足够,不会出现像永久代中 PermGenspace同样的,对永久代的设置参数PermSize和MaxPermSize也会失效。

      默认情况下,“元空间”的大小可以动态调整,或者使用新参数MaxMetaspaceSize来限制本地内存分配给类元数据的大小

      在JDK8里,Perm 区所有内容中,字符串常量移至堆内存,其他内容包括类元信息、字段、静态属性、方法、常量等都移动至元空间。

       元空间的特点:

         此区域没有GC扫描,Full GC时,指向元数据指针都不用再扫描(CMS不会扫描元空间),减少了Full GC的时间,同时减少了内存碎片;

         元空间的对象不会进行转移,也不进行压缩,减少数据转移压缩的开销;

         除非某个类加载器死亡,否则不会对此区域进行回收;

  JVM关闭?

    正常情况下,当随后的非守护线程结束,或调用退出指令(如System.exit(); )JVM正常关闭;

    若系统运行遇到异常信息,抛出RuntimeException时,也会退出,属于异常关闭;

    还有强制执行kill命令,杀死进程,或者是调用Runtime.halt(),这种属于强制关闭。

  JVM如何调优?

    啥?你问为什么需要JVM优化?这我TM...唉...

      肯定是程序出问题了呀,不然还能怎么呐?如程序运行卡停、无反应、CPU负载突然过高... ...

    通常进行JVM调优时,都会先清楚是哪部分代码的问题,这是就需要使用命令或者使用工具来进行排查了。

      命令行工具,这个没有具体使用过;可以使用Jconsole、JVisualVM等来查看java线程执行(如热点代码分析、内存泄漏检查等),此处就不介绍了...嘿嘿,因为工具嘛,使用也不难...

      JVM相关调优链接:https://pengjiaheng.iteye.com/blog/552456

                 http://baijiahao.baidu.com/s?id=1601240621385314413&wfr=spider&for=pc

    具体如何调整呢?

      最终的结果是使用现有的硬件消耗承载最大的系统请求吞吐量

      主要是达到两个目的:一使GC次数减少,二使GC时间减少。与其说减少,不如说过分的少。不过这两者之间的关系是相互矛盾的,因此需要在两者之间进行性能权衡,当然也可以根据不同的GC算法来选择不同的GC收集器。具体调整是根据当前线程的执行情况来决定。

    本节中有部分未完善,会在后续博文中更新...烦请稍作等待...

转载于:https://www.cnblogs.com/fn-f/p/11055181.html

JVM-java虚拟机空间模型相关推荐

  1. Java 虚拟机内存模型

    一.前言 Java 虚拟机,简称 JVM(Java Virtual Machine),是 Java 语言中最为核心的一个东西,Java 程序运行离不开它,因为它的存在,使得 Java 拥有" ...

  2. 【Android 内存优化】Java 内存模型 ( Java 虚拟机内存模型 | 线程私有区 | 共享数据区 | 内存回收算法 | 引用计数 | 可达性分析 )

    文章目录 一. Java 虚拟机内存模型 二. 程序计数器 ( 线程私有区 ) 三. 虚拟机栈 ( 线程私有区 ) 四. 本地方法栈 ( 线程私有区 ) 五. 方法区 ( 共享数据区 ) 1. 方法区 ...

  3. JVM(java 虚拟机)

    JVM(java 虚拟机) 一.JVM简介 1.JVM:Java Virtual Machine (java 虚拟机) 通过软件来模拟出来的具有完整的硬件系统功能.运行在完全隔离的环境中的完整的计算机 ...

  4. JVM——Java虚拟机架构

    Java虚拟机(Java virtualmachine)实现了Java语言最重要的特征:即平台无关性. 平台无关性原理:编译后的 Java程序(.class文件)由 JVM执行.JVM屏蔽了与具体平台 ...

  5. 小白都能看得懂的java虚拟机内存模型

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:土豆是我的最爱 blog.csdn.net/qq_37141 ...

  6. Java虚拟机内存模型初步学习

    Java虚拟机-Java8内存模型 1.概述 对于Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要手动释放内存,不容易出现内存泄露和内存溢出问题.一旦出现内存泄露和溢出方面的问题,如果不 ...

  7. java虚拟机内存模型与垃圾回收知识复习总结

    今天日子很特殊,1024程序员节,本来每个月计划的是至少一篇博客,刚好这个月还没写,今天的日志又特殊,必须要写一篇博客. 之前看过一些讲java虚拟机的课程,但是学过容易忘,总结一下,平时可以多看看. ...

  8. java虚拟机系列:java虚拟机内存模型

    java内存模型,分为程序计数器,虚拟机栈,本地方法栈,java堆,java栈.根据受访的权限不同设置,可以分为线程共享和线程私有.线程共享指可以允许所有的线程共享访问的一类内存区域,包括堆内存区,方 ...

  9. Java虚拟机内存模型简单介绍

    一.虚拟机 同样的java代码在不同平台生成的机器码肯定是不一样的,因为不同的操作系统底层的硬件指令集是不同的. 不知道同学们还记不记得,在下载jdk的时候,我们在oracle官网,基于不同的操作系统 ...

最新文章

  1. 多线程模式(2):Guarded Suspension模式
  2. BZOJ 3160 FFT+Manacher
  3. 最短路径dijkstra
  4. 图书资料管理课程设计(附源码和连接)
  5. Spring MVC:高级会话
  6. 各大银行对应的字段(仅做参考)
  7. 容器宿主机数据库_解决Docker容器内访问宿主机MySQL数据库服务器的问题
  8. selenium之截图
  9. C语言进行可视化编程
  10. Python爬虫获取租房数据
  11. Drools实战-个人所得税计算器
  12. 手把手教你如何连接阿里云RDS云数据库
  13. coreldraw水涟漪怎么做_巧用CorelDRAW X7制作波纹效果文字
  14. 使用java+OpenCV进行图片对比并标记差异部分(支持中文图片路径)
  15. 网易互娱2017实习生招聘在线笔试第一场-题目3
  16. CCS2020论文泛读记录
  17. Revit建模:使用技巧【族类应用】希望能帮大家提高效率
  18. linux添加javahome
  19. [Jquery]天气接口简单使用
  20. Windows 那些坑

热门文章

  1. OpenLayers基础教程——常规的地图控件
  2. WIN10磁盘100%解决方法
  3. win11下链接企业级网络失败的解决方案
  4. 2D/3D文档查看器ABViewer发布v12,大大提高PDF转DWG的速度丨附下载
  5. C语言:函数调用逆序输出
  6. 有限补拓扑与Hausdorff空间与紧致空间
  7. 基于VC709开发板的光纤收发的调试与实现,以及过程中遇到的问题与解决。
  8. 数据结构考研复试、工作面试常见问题及答案(动画版)
  9. UltraISO制作U盘启动盘安装Win7/9/10系统攻略
  10. AI之路(二)——关于统计学习(statistical learning)Part 1 概论