Java虚拟机内存划分以及垃圾回收机制

Java内存动态分配及垃圾回收机制

Java中虚拟机自动内存管理机制,不需要为每一个new操作去匹配delete/free代码,不容易出现内存泄漏和内存溢出的问题。Java虚拟机享有内存管理的控制权。

运行时数据区域

Java虚拟机在执行Java程序的过程中会将管理的内存分为不同的数据区域,

  • 每个区域有不同的用途,存储不同的内容
  • 每个区域有各自的创建以及销毁时间
    Java虚拟机内存划分以及垃圾回收机制

1.1 程序计数器 Program Counter Register

当前线程所执行的字节码的行号指示器,在JVM概念模型中,字节码解释器根据程序计数器中值选取下一条需要执行的字节码指令(分支、循环、跳转、异常处理、线程恢复等都依赖于计数器实现)

  • java多线程是通过线程轮流获取CPU控制权实现的,而在某个确定的时刻,一个处理器(多核中某一个内核)只有一个线程在运行,其他线程在等待。线程轮换后回到正确的执行位置时就需要程序计数器,
  • 于是每个线程都需要一个独立的程序计数器,各线程之间计数器互不影响,独立存储。这类内存区域称之为线程私有的内存

是否线程私有: 是
可能导致的异常 : 无

1.2 Java虚拟机栈 Java Virtual Machine Stacks

存放局部变量表操作数栈动态链接方法出口等信息。
常说的栈内存堆内存的概念,其实就是指Java虚拟机栈中局部变量表部分。

  • 局部变量表: 存放了编译期可知的各种基本数据类型(boolean、byte、char等)、对象引用(reference类型,不是对象本身,只是一个活跃的引用指针。具体解释需百度)和returnAddress类型
  • 局部变量表所需的内存空间在编译期间已经完成分配,当进入方法时,方法需要多大的局部变量空间是确定的,不会在方法运行期间改变局部变量表的大小

生命周期: 随着线程创建、销毁
是否线程私有: 是
可能导致的异常

  1. StackOverflowError异常,虚拟机请求的栈深度大于虚拟机所允许的深度
  2. OutOfMemoryError异常,虚拟机栈允许动态扩展,但在扩展时无法申请到足够的内存

1.3 本地方法栈 Native Method Stack

名称 作用 异常
Java虚拟机栈 为虚拟机执行Java方法服务 StackOverflowError、OutOfMemoryError
本地方法栈 为虚拟机中使用到的Native方法服务 同上

1.4 Java堆 Java Heap

  1. 被所有线程共享的一块内存区域
  2. 存放对象实例,Java虚拟机规范中要求:所有的对象实例以及数组都要在堆上分配
  3. 垃圾收集器管理的主要区域,目前收集器基本都采用分带手机算法(新生代、老年代)
  • Java堆可以处于武理上不连续的内存空间,只要逻辑上是连续的即可(虽然可能会导致其他内存碎片的问题吧)
  • 堆大小既可以是固定的,也可以是可扩展的(-Xmx(程序运行期间最大可占用的内存大小)和-Xms(程序启动时占用内存大小)控制)

生命周期: 在虚拟机启动时创建
是否线程私有: 否
可能导致的异常

  1. OutOfMemoryError异常:堆中没有内存完成实例分配,且堆也没办法再继续扩展

1.5 方法区 Method Area

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

  • 该区域的内存回收目的主要针对常量池的回收和对类型的卸载

生命周期: 在虚拟机启动时创建
是否线程私有: 否
可能导致的异常 :OutOfMemoryError异常:方法区无法满足内存分配需求

运行时区域 存放内容
Java虚拟机栈 局部变量表 (基本数据类型 & 对象引用等)、操作数栈、动态链接、方法出口’
Java堆 对象实例 、数组
方法区 虚拟机加载的类信息、常量、静态变量