深入理解JVM-内存模型

来源:互联网 发布:php com dotnet.dll 编辑:程序博客网 时间:2024/06/05 20:52

        最近一直在研究这个JVM,看了一本书《深入理解Java虚拟机》,来记录一下这一段的学习历程。Java虚拟机内存分析,初研究感觉好像很难理解,其实跟日常我们编程有很大的关系,理解Java虚拟机对我们提升代码质量也有很大的帮助。

       JVM虚拟机运行时数据区:

       


       程序计数器:

       一块较小的内存空间,可看作是当前线程执行的字节码的行号指示器。

       虚拟机的概念模型中,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、          跳 转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

       Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间来实现的,在任何一个确定的时刻,一个处理器(对于多核处          理器来说是一个内核)都只能执行一条线程中的指令。为了线程切换能准确恢复到正确的位置,每条线程都需要一个独立的程          序计数器,各线程之间计数器互不影响,独立存储,所以这类内存区域为“线程私有”。

       如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方          法,这个计数器值则为空。


      虚拟机栈:

        线程私有,生命周期和线程相同。Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧,用于存储局部变量             表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到           出栈的过程。

      局部变量表:

        局部变量表存放了编译期可知的基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用和

        returnAddresss类型(指向了一条字节码指令的地址)。


     本地方法栈:

       本地方法栈和虚拟机所发挥的作用是非常相似的,区别是:虚拟机栈为虚拟机执行Java方法服务,本地方法栈则为虚拟机使

       用Native方法服务。在虚拟机规范中对本地方法中使用的语言、使用方式和数据结构并没有强制规定,因此具体的虚拟机可以

       自由实现它。


     堆:

        被所有线程共享的一块内存区域。对大多数的应用来说,Java 堆是Java虚拟机所管理的内存中最大的一块,在虚拟机启动

        时创建。该内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。

        Java堆是垃圾收集器管理的主要区域,因此也被称作“GC堆”。由于现在收集器基本都采用分代收集算法,Java堆可以细分为:

        新生代和老年代。

        1、新生代:

         新生代用于存放刚创建的对象以及年轻的对象,新生代又可进一步细分为eden、survivorSpace0(s0,from space)、                            survivorSpace1(s1,to space)。刚创建的对象都放入eden,s0和s1都至少经过一次GC并幸存。

         2、老年代:

         用于存放经过多次新生代GC仍然存活的对象,例如缓存对象,新建的对象也有可能直接进入老年代,主要有两种情况:

         (1)大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在

              新生代分配,而是直接在老年代分配。

         (2)大的数组对象,且数组中无引用外部对象。
             老年代所占的内存大小为-Xmx对应的值减去-Xmn对应的值。
 
             如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常。

    方法区:

        线程共享的内存区域,它用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。


   运行时常量池:

         方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool 

         Table),用于存放编译期生成的各种字面量和符号引用,这部分内容在类加载后进入方法区的运行时常量池中存放。

         特点是:相对于Class文件常量池是具有动态性。Java语言并不要求常量一定只有编译期才能产生,也并非预置入Class文件

         中的常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中。

         由于是方法区的一部分,也受到方法区内存限制,当常量池无法在申请到内存时会抛出OutOfMemoryError异常。     


       



0 0
原创粉丝点击