1. 前言

这是深入理解java虚拟机一书的笔记,来自第二章。因为这本书讲的比较深奥,这是第二次看,需要记录一下笔记。

2. 运行时数据区域

java虚拟机所管理的内存分为以下几个区域。

图片来自他人博客

ps:图片来自网络

2.1 程序计数器

程序计数器是一块较小的内存空间,他可以看做是当前线程所执行字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选去下一条要执行的字节码指令,分之、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
这块内存是线程私有的内存。
如果线程在执行java方法,那么这个计数器记录的就是正在执行的虚拟机字节码指令的地址,如果是native方法,计数器为空,此内存区域是java虚拟机规范中不存在oom的区域。

2.2 java虚拟机栈

也是线程私有的,虚拟机栈描述的是java方法执行的内存模型,每个方法在执行的同时会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息,没一个方法从调用直刀执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈和出栈的过程。
局部变量表存放来编译器可知的各种基本数据类型、对象引用类型,不同与对象本身,可能是指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或与其他与对象相关的位置。

2.3 本地方法栈

本地方法栈则为虚拟机使用的native方法服务。

2.4 java 堆

是虚拟机中内存最大的一块地区,是线程共享的,几乎所有的对象实例都在这里分配内存,所有的对象实例以及数组都要在堆上分配。

2.5 方法区

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

2.6 运行时常量池

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

2.7 直接内存

并不是虚拟机中的一部分,诸如nio等等。

3. 对象的创建

虚拟机遇到一条new指令时,去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否被加载、解析和初始化,如果没有,执行类加载的过程,通过之后,虚拟机为新生对象分配内存,需要的内存在类加载完成之后就完全确定了。内存分配完成之后,虚拟机对对象进行必要的设值。

指针碰撞:

假设内存是绝对完整的,中间放一个指针区分使用和空闲内存,分配对象的时候,指针移动和对象大小相同的一块区域,叫做指针碰撞。

空闲列表:

如果是不完整的,虚拟机就需要记录下那块内存可用,那块内存不可用,分配内存的时候从可用列表找出够大的一块内存分配。

4. 对象的访问定为

  • 句柄
  • 直接指针

5. 内存溢出

  • java堆溢出
  • 虚拟机栈和本地方法栈溢出
  • 方法区运行时常量池溢出
  • 本机直接内存溢出
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐