公司新闻

Java内存区域

JAVA程序对它所管理的内存区域进行划分,分为堆、方法区、虚拟机栈、本地方法栈、程序计数器。

1. 程序计数器

  1. 1. 一块较小的内存空间,线程所私有,看作当前线程所执行的字节码的行号指示器。
  2. 2. 如果执行的是JAVA方法,计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是本地方法,这个计数器值为空。
  3. 3. 唯一没有规定任何OutOfMemoryError情况的区域。

2. JAVA虚拟机栈

1.线程所私有,生命周期和当前线程相同。虚拟机栈描述的是JAVA方法执行的线程内存模型:每个JAVA方法执行时都会同步创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态连接、方法出口等信息。
2.局部变量表存放了编译期可知的基本数据类型、对象引用类型、和returnAddress类型。
3.这些护具类型在局部变量表中的存储空间以局部变量槽(Slot)来表示,其中64位长度的long和double类型会占用两个变量槽,其余类型只占用一个。
4.当进入方法时,需要的栈帧分配的局部变量空间是确定的,指变量槽的数量,具体的内存空间需要根据单个变量槽所占用比特决定,由具体虚拟机实现确定。
5.该区域规定了两类异常,分别是StackOverflowError和OutOfMemoryError异常。如果线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverflowError,如果JAVA虚拟机栈容量可以的动态扩展,当栈扩展时,无法申请到足够的内存会抛出OutOfMemoryError。

3. 本地方法栈

为虚拟机使用到的本地方法服务。

JAVA堆

是所有线程共享的且是虚拟机管理的最大的一块内存区域,用于存放对象实例。

5. 方法区

是线程共享的、用于存储已加载的类型信息、常量、静态 变量、即时编译器编译后的代码缓存等数据。

运行时常量池

是方法区的一部分,用于存放类的常量池表,存放编译期生成的各种字面量与符号引用。

7. 对象的创建

7.1 分配内存方式

分配对象时,在类加载通过后就可以确定内存的大小,根据JAVA堆的内存是否规整,内存分配分两类:
指针碰撞:JAVA堆内存规整,所有被使用过的内存放一边,未被使用过的内存放另一边,中间放着一个指针作为分界点的指示器,通过往未使用过的内存一边挪动一段与对象大小相等的距离,来完成对对象内存的分配。
空闲列表:JAVA堆内存不规整,需要维护一个空闲列表,来标注可用的内存区域,在分配内存时,在列表上找到一块足够大的空间划分给对象使用,并更新列表上的记录。

7.2 安全分配内存

为了在多线程情况下,保证分配对象的线程安全性,有两种方案:
采用CAS配上失败重试的方式保证更新操作的原子性。
把内存分配的动作按照线程划分在不同的空间中进行。