JVM学习总结(一)运行时数据区

《深入Java虚拟机》这本书买了有一段时间了,当时看的时候就只是看,并没有边看边总结啥的,最后发现到脑子里面的根本所剩无几了。现在开始要好好归纳总结地再学习一遍。

运行时数据区域

JVM在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。所管理的内存包括以下几个运行时数据区域

输入图片说明

  1. 程序计数器
  • 作用:记录当前线程所执行的字节码的行号。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令
  • 意义:JVM的多线程是通过线程轮流切换并分配CPU时间方式来实现的,因此,为了线程切换后能恢复到正确的指定位置,每条线程丢都需要一个独立的程序计数器
  • 存储内容 : 若线程正执行的是一个Java方法时,程序计数器中记录的是正在执行的线程的虚拟机字节码指令的地址 若线程正执行的是一个本地方法时,程序计数器中的值为空
  • 可能发生的异常: 程序计数器是唯一一个Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域
  1. Java虚拟机栈
  • 作用:描述Java方法执行的内存模型,每个方法执行的时候都会创建一个栈帧,栈帧里面存储了局部变量表、操作数栈、动态链接、方法出口等信息
  • 意义:方法从开始执行到执行结束,就对应着一个栈帧在Java虚拟机栈中入栈到出栈的过程
  • 存储内容: 局部变量表(编译期间可知的各种基本数据类型、引用类型和指向一条字节码指令的returnAddress类型)、操作数栈、动态链接、方法出口等信息 值得注意的是:局部变量表所需的内存空间在编译期间完成分配。在方法运行的阶段是不会改变局部变量表的大小的
  • 可能发生的异常: StackOverflowError异常:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出该异常 OutOfMemoryError异常:如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可以动态扩展,只不过虚拟机规范中也允许固定长度的虚拟机栈)如果扩展时无法申请到足够的内存,就会抛出该异常
  1. 本地方法栈
  • 作用:为JVM所调用到的Native即本地方法服务 ps:Sun HotSpot虚拟机 直接把本地方法栈和虚拟机栈合二为一
  • 可能发生的异常:同虚拟机栈,存在StackOverflowError异常和OutOfMemoryError异常
  1. Java堆
  • 作用:分配所有的对象实例以及数组,但随着即时编译(JIT)器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术使得对象都在对上分配变得不那么绝对
  • 意义:Java堆是Java虚拟机所管理的内存中最大的一块,被所有线程共享,在JVM启动时创建。Java堆是垃圾收集器管理的主要区域,Java堆可以细分为:新生代(Young Generation)、老年代(Old Generation)、永久代(Permanent Generation);新生代再细致一点可以分为Eden空间、From Survivor空间、To Survivor空间。如果配置-XX:+/-UseTLAB,每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)
  • 存储内容: 存放对象实例及数组(创建数组时,创建动作由字节码指令newarray触发,虚拟机自动生成一个为java.lang.Object的子类的类,这个类中实现了数组中应有的属性和方法,可以直接访问的为public类型的length属性和clone()方法),几乎所有的对象实例都在这里进行分配。堆可以处于物理上不连续的内存空间,只要逻辑上是连续的就可以
  • 可能发生的异常:如果堆中没有内存完成实例分配,并且堆也无法再拓展(堆可以是固定大小的,拓展可通过-Xms和-Xmx参数控制)时,将会抛出OutOfMemoryError异常
  1. 方法区
  • 作用:用于存储运行时常量池、已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
  • 意义:对运行时常量池、常量、静态变量等数据做出了规定
  • 存储内容:运行时常量池(具有动态性)、已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
  • 可能发生的异常:当方法区无法满足内存分配需求的时候抛出OutOfMemoryError异常

运行时常量池

运行时常量池是方法区的一部分。Class文件中出了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期间生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池存放

jdk6、jdk7、jdk8对于方法区的设计不同

  • 运行时常量池在JDK1.6及之前版本的JVM中是方法区的一部分,而在HotSpot虚拟机中方法区放在了”永久代”。所以运行时常量池也是在永久代的
  • 但是JDK1.7及之后版本的JVM已经将运行时常量池从方法区中移了出来,在Java 堆(Heap)中开辟了一块区域存放运行时常量池
  • 而在JDK1.8中,已经彻底没有了永久代,将方法区直接放在一个与堆不相连的本地内存区域,这个区域被叫做元空间

猜你喜欢

转载自my.oschina.net/hensemlee/blog/1799189
今日推荐