java内存机制
Java 内存类型
Java 主要分为两部分运行时数据区,一部分是与进程相关的,
进程启动时创建,进程结束时销毁,这部分的内存属于线程共享的;
另一部分则是线程相关的, 线程启动时创建,线程结束时销毁,
线程间不共享。
系统启动之后, 除了会创建一个进程之外,
也会同时启动至少两个线程,一个为main方法启动的线程,另一个为垃圾回收的线程;
进程级别数据区
-
方法区,
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
主要是堆的逻辑部分。
该区域垃圾收集比较少,有一定内存泄漏的风险。
- 运行时常量池
, 用于存储Class文件中的用于存放编译器生成的字面量和符号引用,
以及运行时生成的常量。
-
堆(Heap),
用于存放对象实例,数组。
是垃圾回收管理的主要区域, 从垃圾回收角度,Java堆还可以分为新生代和老年代。
从内存分配角度,Java堆可能划分出多个线程私有的分配缓冲区。
Java堆可以处于物理上不连续的内存空间,只要逻辑上连续即可,既可以实现成固定大小的,也可以实现成可扩展的。
可能会抛出OutOfMemoryError异常。
线程级别数据区
-
程序计数器, 一块较小的内存空间,作为当前线程所执行的字节码的行号指示器。
-
虚拟机栈,
虚拟机栈用来描述Java方法执行的内存模型, 每个方法在执行的同时,
会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
每一个方法从调用到执行完成的过程,对应一个栈帧在虚拟机栈中入栈到出栈的过程。
-
局部变量表, 存放了编译器可知的基本数据类型、对象引用句柄等,
既一般所谓Java内存堆和栈中的栈的概念。
在编译器已经确定一个方法需要申请多大局部变量空间,方法运行过程中将不会改变。
方法运行时,将按需申请局部变量空间,如果空间不够,将抛出StackOverflowError异常; 如果虚拟机可以动态扩展,但是无法申请足够内存,将抛出 OutOfMemoryError异常。
-
操作数栈
-
动态链接
-
方法出口
-
本地方法栈, 为虚拟机执行Native方法服务。本地方法栈也会有可能抛出StackOverflowError和OutOfMemoryError异常。
直接内存
直接内存不是虚拟机运行时数据区一部分。
是NIO类中引入的,在基于通道与缓冲区的I/O方式,可以使用Native函数库直接分配堆外内存,然后通过Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。可以提高性能,避免Java堆和Native堆中来回复制数据。
其不受Java堆大小限制,但是受物理机内存限制。
垃圾回收相关
待深入研究的地方
- Java方法和Native方法具体区别
- Java堆中多个线程共享的缓冲区示例
- Java堆中对象的具体存储
- 内存的执行过程变化
- 操作数栈、动态链接、方法出口等
- 关于直接内存的扩展,文件访问方式