Java虚拟机内存划分以及垃圾回收机制
Java内存动态分配及垃圾回收机制
Java中虚拟机自动内存管理机制,不需要为每一个new操作去匹配delete/free代码,不容易出现内存泄漏和内存溢出的问题。Java虚拟机享有内存管理的控制权。
运行时数据区域
Java虚拟机在执行Java程序的过程中会将管理的内存分为不同的数据区域,
- 每个区域有不同的用途,存储不同的内容
- 每个区域有各自的创建以及销毁时间
1.1 程序计数器 Program Counter Register
当前线程所执行的字节码的行号指示器,在JVM概念模型中,字节码解释器根据程序计数器
中值选取下一条需要执行的字节码指令(分支、循环、跳转、异常处理、线程恢复等都依赖于计数器实现)
- java多线程是通过线程轮流获取CPU控制权实现的,而在某个确定的时刻,一个处理器(多核中某一个内核)只有一个线程在运行,其他线程在等待。线程轮换后回到正确的执行位置时就需要
程序计数器
, - 于是每个线程都需要一个独立的程序计数器,各线程之间计数器互不影响,独立存储。这类内存区域称之为
线程私有的内存
是否线程私有: 是
可能导致的异常 : 无
1.2 Java虚拟机栈 Java Virtual Machine Stacks
存放局部变量表、操作数栈、动态链接、方法出口等信息。
常说的栈内存和堆内存的概念,其实就是指Java虚拟机栈中局部变量表部分。
- 局部变量表: 存放了
编译期
可知的各种基本数据类型(boolean、byte、char等)、对象引用(reference类型,不是对象本身,只是一个活跃的引用指针。具体解释需百度)和returnAddress类型 - 局部变量表所需的内存空间在编译期间已经完成分配,当进入方法时,方法需要多大的局部变量空间是确定的,不会在方法运行期间改变局部变量表的大小
生命周期: 随着线程创建、销毁
是否线程私有: 是
可能导致的异常 :
- StackOverflowError异常,虚拟机请求的栈深度大于虚拟机所允许的深度
- OutOfMemoryError异常,虚拟机栈允许动态扩展,但在扩展时无法申请到足够的内存
1.3 本地方法栈 Native Method Stack
名称 | 作用 | 异常 |
---|---|---|
Java虚拟机栈 | 为虚拟机执行Java方法服务 | StackOverflowError、OutOfMemoryError |
本地方法栈 | 为虚拟机中使用到的Native方法服务 | 同上 |
1.4 Java堆 Java Heap
- 被所有线程共享的一块内存区域
- 存放对象实例,Java虚拟机规范中要求:所有的
对象实例
以及数组
都要在堆上分配 - 垃圾收集器管理的主要区域,目前收集器基本都采用分带手机算法(新生代、老年代)
- Java堆可以处于武理上不连续的内存空间,只要逻辑上是连续的即可(虽然可能会导致其他内存碎片的问题吧)
- 堆大小既可以是固定的,也可以是可扩展的(
-Xmx
(程序运行期间最大可占用的内存大小)和-Xms
(程序启动时占用内存大小)控制)
生命周期: 在虚拟机启动时创建
是否线程私有: 否
可能导致的异常 :
- OutOfMemoryError异常:堆中没有内存完成实例分配,且堆也没办法再继续扩展
1.5 方法区 Method Area
各个线程共享的内存区域,用于存储已被虚拟机加载的·类信息、常量、静态变量、即时编译器编译后代码
- 该区域的内存回收目的主要针对常量池的回收和对类型的卸载
生命周期: 在虚拟机启动时创建
是否线程私有: 否
可能导致的异常 :OutOfMemoryError异常:方法区无法满足内存分配需求
运行时区域 | 存放内容 |
---|---|
Java虚拟机栈 | 局部变量表 (基本数据类型 & 对象引用等)、操作数栈、动态链接、方法出口’ |
Java堆 | 对象实例 、数组 |
方法区 | 虚拟机加载的类信息、常量、静态变量 |