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堆中对象的具体存储
  • 内存的执行过程变化
  • 操作数栈、动态链接、方法出口等
  • 关于直接内存的扩展,文件访问方式