[Java学习小笔记]自动内存管理机制

150 阅读3分钟

运行时数据区域

Java运行时数据区


程序计数器

  • 一块较小的内存空间

  • 当前线程所执行的字节码的行号指示器

  • 字节码解释器改变这个指示器的值来选择下一条执行的字节码指令

  • 每条线程有一个独立的计数器(线程私有),目的保证在切换线程的时候保证能恢复到正确的执行位置

  • native方法计数器值为空,此区域没规定OOM


Java虚拟机栈

  • 线程私有,生命周期与线程相同

  • Java执行的内存模型,在执行时创建栈帧,存局部变量表、操作数栈、动态链接、方法出口等信息

  • 方法从调用结束,对应着其栈帧入栈出栈

  • 局部变量表(编译期间完成分配,进入发发钱局部变量空间为完全确定的)

    • 编译期可知的基本数据类型
      • (boolean,byte,char,short,int,float.long,double)
      • 64位long和double占用2个局部变量空间,其余数据类型只占用一个
    • 对象引用,reference类型,是指向一个对象起始地址的引用指针、或指向一个代表对象的句柄或其他于此对象相关的位置
    • returnAddress类型,指向一条字节码指令的地址
  • 栈深度大于虚拟机所允许的深度会抛出StackOverflowError

  • 如果可以动态拓展,但无法申请到足够的内存,抛出OutOfMemory

本地方法栈

Differences between Natvie Method Stack and Java Virtual Machine Stacks

  1. 本地方法栈虚拟机为Native方法服务

  2. 虚拟机栈为Java方法(字节码)服务


Java堆

  • 虚拟机启动时创建

  • 目的:

    • 存放对象实例几乎所有对象实例都在这里分配内存(!随着栈上分配、标量替换优化技术会导致所有对象分配在栈上不是那么绝对)
    • 辣鸡收集器管理的主要区域(GC堆)
  • 分类方式:

    • 内存回收(分代收集算法):新生代老年代

    • 内存分配:划分出线程私有的分配缓冲区(TLAB)

  • 无论哪个区域,储存的都是对象实例,与内容无关

  • 可以处于不连续的内存空间中、逻辑需连续

  • 怼中没有内存完成实例分配,并且堆无法再拓展时候,会抛出OutOfMemoryError


方法区

  • 目的:用于储存已被虚拟机加载的类信息、常亮、静态变量、即时编译器编译后的代码
  • Difference with heap
    • heap经常发生GC进行垃圾收集,而方法区约等于“永久态”(! 不是永久存在,有对常量池的回收及对类型的卸载,但是条件比较苛刻)
    • 个人理解主要目的是为了进行内存优化,像常亮这类不需要频繁GC的适合放在方法区
  • 运行时常量池

    • 方法区的一部分
    • 存放编译器生成的各种字面量和符号引用
    • 不一定是定义在Class文件内部的常量池才会进入运行时候常量池,运行期间有可能将新的常亮放入池中(String的intern())
    • 无法再申请内存的时候抛出OutOfMemoryError

直接内存

  • 不属于虚拟机运行时数据区
  • 可以使用Native函数库直接分配heap外内存,通过Java堆中DirecrByteBuffer对象作为这块内存的引用进行操作
  • 作用:提高性能,避免Java堆和Native堆中来回复制数据