谈谈对JVM的理解

        JVM可谓是学习JAVA基础中的基础了,但仍有很多同窗对JVM概念仍是比较模糊,甚至没有据说过,对java的理解也只是在基础语法 层面,本文就将对JVM进行初步介绍,因篇幅所限,只能介绍JVM基础,如须要进一步学习,建议阅读机械工业出版社出版的《深刻理解JAVA虚拟机》。

        请尊重做者劳动成果,转载请标明原文连接:html

   http://www.noobyard.com/article/p-rfgmsnav-mm.htmljava

        Java虚拟机规范中规定的JVM以下图所示:
        能够看出,JVM由JVM运行时数据区(图示中蓝色框包含部分)、执行引擎、本地库接口、本地方法库组成。
 
        JVM运行时数据区,分为线程共享部分(方法区、堆)和线程隔离区(虚拟机栈、本地方法栈和程序计数器)。
        1.方法区
         用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
        运行时常量池(Runtime Constant Pool)是方法区的一部分。.Class文件中除了有类的版本/字段/方法/接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各类字面量和符号引用,这部份内容将类在加载后进入方法区的运行时常量池中存放.
运行时常量区的内容并不仅是在编译期间产生,经过String.intern()也能够实如今运行时向常量区中添加内容。
        须要注意的是:从JDK8开始,方法区被元数据区替代了。具体的缘由和二者的区别能够参考官网。
 
        2.堆
        是JVM中最大的一块内存区域,该区域的目的只是用于存储对象实例及数组。该区域也是GC的最主要区域。
        根据Java虚拟机规范的规定,Java堆能够处于物理上不连续的内存空间中,只要逻辑上是连续的便可,就像咱们的磁盘空间同样.在实现时,既能够实现固定大小的,也能够是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的(经过-Xmx和-Xms控制).若是在堆中没有内存完成实例分配,而且堆也没法再扩展时,就会抛出OutOfMemoryError异常。
 
        3.虚拟机栈
        每一个线程方法在执行时都会建立一个栈帧,包含局部变量表、返回地址、操做数栈等信息。每一个方法的执行与完成就对应的栈帧的入栈与出栈过程 。局部变量表占用空间的大小在编译期就肯定了。这里须要注意:若是线程请求的栈深度大于虚拟机所容许的深度,将会抛出StackOverflowError异常;若是虚拟机栈能够动态扩展(当前大部分的Java虚拟机均可动态扩展,只不过Java虚拟机规范中也容许固定长度的虚拟机栈),当扩展时没法申请到足够的内存时将会抛出OutOfMemoryError异常。
 
        4.本地方法栈
        与虚拟机栈相似,不过其中执行是本地方法。对于HotSpot虚拟机而言,本地方法栈和虚拟机栈是统一的。
 
        5.程序计数器
       是一个小的内存空间,若是线程正在执行的是一个java方法,则此内存区域记录正在执行的虚拟机字节码指令的地址;若是线程正在执行的是native方法,则计算器中的值为空。此内存区域是惟一一个在JAVA虚拟机规范中没有规定任何OutOfMemoryError状况的区域。
 
        这几部分都有相关的JDK自带工具能够分析查看,好比jps, jstack, jmap, jhat, jstat等,还有图形化工具jconsole,jvisualvm,但对于Linux服务器就无能为力了。
 
        好了,关于JVM就讲完了,接下来进行提问:JVM哪些区域会发生OOME,以及各自缘由是什么?
 
        堆内存不足是最多见的 OOM 缘由之一,抛出的错误信息是“java.lang.OutOfMemoryError:Java heap space”,缘由可能千奇百怪,例如,可能存在内存泄漏问题;也颇有可能就是堆的大小不合理,好比咱们要处理比较可观的数据量,可是没有显式指定 JVM 堆大小或者指定数值偏小;或者出现 JVM 处理引用不及时,致使堆积起来,内存没法释放等。
        而对于 Java 虚拟机栈和本地方法栈,这里要稍微复杂一点。若是咱们写一段程序不断的进行递归调用,并且没有退出条件,就会致使不断地进行压栈。相似这种状况,JVM 实际会抛出 StackOverFlowError;固然,若是 JVM 试图去扩展栈空间的的时候失败,则会抛出 OutOfMemoryError。
        对于老版本的 Oracle JDK,由于永久代的大小是有限的,而且 JVM 对永久代垃圾回收(如,常量池回收、卸载再也不须要的类型)很是不积极,因此当咱们不断添加新类型的时候,永久代出现 OutOfMemoryError 也很是多见,尤为是在运行时存在大量动态类型生成的场合;相似 Intern 字符串缓存占用太多空间,也会致使 OOM 问题。对应的异常信息,会标记出来和永久代相关:“java.lang.OutOfMemoryError: PermGen space”。
        随着元数据区的引入,方法区内存已经再也不那么窘迫,因此相应的 OOM 有所改观,出现 OOM,异常信息则变成了:“java.lang.OutOfMemoryError: Metaspace”。
        直接内存不足,也会致使 OOM。
 
        后记:
        JVM是JAVA面试过程当中最容易被问到的基础题目,在本篇JVM介绍完后,后面还准备了更多有意思的JAVA基础面试题,这些将做为提高JAVA基础能力的免费系列课程,从面试题出发,对每一个问题触类旁通,以点带面,不作不求甚解之人,最终目标不是学会答题,而是学会题目自己涉及到的全部知识点。暂定的所有面试题目课程包含以下内容:
        谈谈你对JVM的理解?
        final,finally,finalize有什么区别?
        String,StringBuffer,StringBuilder有什么区别?
        Exception和Error有什么区别?
        Hashtable,HashMap,TreeMap有什么区别?
        Vector,ArrayList,LinkedList有什么区别?
        int和Integer有什么区别?
        接口和抽象类有什么区别?
        如何保证集合是线程安全的?
        谈谈你知道的设计模式?
 
        搜索关注微信公众号“程序员姜小白”,获取更新精彩内容哦。