• 程序计数器: 没有OOM, 线程私有, 线程间互不干扰, 用来指示线程执行指令地址的. Native方法没有计数器值.

  • 虚拟机栈: 线程私有, 生命周期同线程, 方法在执行的时候会创建一个栈帧用来存局部变量, 动态链接, 方法出口等信息. 一个方法从调用到执行完毕, 对应着一个栈帧从入栈到出栈. 通常被称为”栈内存”.

    当线程请求的栈深度大于虚拟机所允许的深度, 抛出StackOverflowError.

  • 如果虚拟机栈可以动态扩展(Java可以动态扩展也可以固定长度), 在扩展时若无法申请到足够内存则抛出OutOfMemoryError.

  • 本地方法栈: 作用类似虚拟机栈, 不过本地方法栈执行Native方法. 也会有StackOverflowErrorOutOfMemoryError出现.

  • 方法区: 线程共享, 存储类的信息、常量池、方法数据、方法代码(编译器编码后的)等.”java.lang.OutOfMemoryError: PermGen space “就是指的方法区.

  • 堆: 内存最大, 线程共享, 在虚拟机启动时创建. 用作存放对象实例, 也是GC的主要区域.细分为新生代和老年代.

  • 永久代(即方法区): 1.8之后永久代转换成了元空间(Metaspace), 且PermSizeMaxPermSize 会被忽略并给出警告.在1.7中开始移除, 但未完全移除.

    其中原因可能有:

    字符串在永久代中不利于GC, 容易出现性能问题和内存溢出.

    类和方法的信息比较难确定大小, 所以永久带不好指定大小, 大了老年代溢出, 小了永久代溢出

  • 元空间: 元空间内存储的类元数据的生命周期等于该类的类加载器生命周期, 不再单独回收某各类, 且对象的位置是固定的, 当类加载器不再存活, 被gc声明死亡后, 该类加载器对应的空间就会被回收.

    元空间使用-XX:MinMetaspaceFreeRatio-XX:MaxMetaspaceFreeRatio进行调节.

  • 常量池: 方法区的一部分. 用于存放编译期和运行时生成的各种字面量和符号引用. 比如String类的intern方法

  • 直接内存: 也就是堆外内存, NIO可以通过Native函数直接分配, 通过在堆中的DirectByteBuffer作为引用进行操作. 注意内存泄漏导致的OOM.

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

人生中没有四季 唯有那寒冬的荒野