JVM学习笔记(1)--java内存区域与内存溢出异常

运行时数据区域

程序计数器 Program Counter Register

可以看作是当前线程的字节码的行号指示器,为什么说是当前线程呢?因为java的多线程是通过线程轮流切换来实现的,为了切换后能恢复到正确的执行位置,每个线程都要有一个独立的程序计数器,之间互不影响。这块内存区域被称为“线程私有”的内存。

java虚拟机栈VM Stack

  • 我们常说的栈内存就是指虚拟机栈
  • 虚拟机栈也是线程私有的
  • 生命周期与线程相同
  • 描述了java方法执行的内存模型,每个方法执行时,都会创建一个栈帧(stack frame)用于存储局部变量表、操作数栈、动态链接,方法出口等信息,每个方法的调用到完成,对应着栈帧在虚拟机栈中的入栈到出栈的过程
  • 局部变量表用于存放基本数据类型(boolean,byte,char,short,int,float,long,double),对象引用,和returnAddress
  • 该区域会出现两种异常:1.如果线程请求的栈的深度大于虚拟机栈所允许的深度,会抛出StackOverflowError异常。2.若虚拟机栈可以动态扩展(大部分虚拟机都允许),如果扩展时无法申请到足够的内存,则会抛出OutOfMemoryError异常

本地方法栈 Native Method Stack

  • 线程私有
  • 与虚拟机栈类似,唯一区别就是虚拟机栈位虚拟机执行java方法服务,本地方法栈则虚拟机使用的native方法服务
  • 也会抛出StackOverflowError异常与OutOfMemoryError异常

java堆 java heap

  • 是一块被所有线程共享的内存区域,在虚拟机启动的时候创建。
  • 唯一目的就是存放对象(及数组)实例,几乎所有对象实例都在这里分配内存
  • 在堆中没有内存完成实例分配,并且堆无法再拓展的时候,就会抛出OutOfMemoryError异常

方法区

  • 无法满足内存分配时就会抛出OutOfMemoryError异常
  • 用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等

运行时常量池

  • 是方法区的一部分
  • 常量池:用于存放编译期生成的各种字面量(1,2,“abc”称为字面量)和符号引用,这部分内容在类加载后进入方法区的运行时常量池存放
  • 无法满足内存分配时就会抛出OutOfMemoryError异常

直接内存

  • 并不是虚拟机运行时数据区的一部分,是引入NIO类后出现的一块内存。

虚拟机对象

对象内存分配

  • 指针碰撞:要求java堆是规整的!Serial,ParNew
  • 空闲列表:虚拟机维护一个列表,记录哪些内存块是可用的,分配的时候找到一个空间给对象,并更新列表记录。CMS

对象的内存布局

对象在内存中存储的布局可以分为三块:对象头,实例数据,对齐填充
* 对象头:对象自身的运行时数据和类型指针(对象指向他的类元数据的指针)
* 实例数据:对象存储的有效信息
* 对齐填充:对象的大小必须是8字节的整数倍,因此不够得需要补齐

对象的访问定位

java程序需要通过栈中的reference来操作java堆上的具体对象
主流两种方式来访问:使用句柄和直接指针
直接指针节省了一次指针定位的时间

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章