Java Memory Model

JVM内存模型架构

jvm

程序计数器(PC)

  • 当前线程所执行的字节码行号指示器
  • 改变计数器的值来选取下一条需要执行的字节码指令
  • 和线程一一对应
  • 只对Java方法计数,如果是Native方法则计数器值为Undefined
  • 不会发生内存泄漏

Java虚拟机栈(Stack)

  • Java方法执行的内存模型
  • 包含多个栈帧
  • 与方法对应

java.lang.StackOverflowError

stack

  • 局部变量表:包含方法执行过程中所有的变量
  • 操作数栈:入栈,出栈,复制,交换,产生消费变量

eg.递归过深,栈帧超过虚拟栈深度,就会报错

java.lang.OutOfMemoryError

如果虚拟机栈可以动态扩展,并超出内存,就会报此错误

本地方法栈

native方法使用

元空间与永久代

MetaSpace & PermGen

Java8以后,元空间替代了永久代,PermGen Space报错消失

  • 存储Class相关信息

  • 元空间使用本地内存,永久代使用jvm内存

  • 类信息加载空间
  • 线程共享

MetaSpace相比PermGen优势

  • 字符串常量池存在永久代中,容易出现性能问题和内存溢出
  • 类和方法的信息大小难以确定,给永久代的大小指定带来困难
  • 永久代为GC带来复杂度

Java堆(Heap)

  • JVM内存中最大一块
  • 线程共享
  • 对象实例的分配区域
  • GC管理的主要区域

heap

性能调优参数

  • -Xss:规定每个线程虚拟机(堆栈)大小,影响并发线程数大小(256K)
  • -Xms:堆的初始值
  • -Xmx:堆动态扩容能达到的最大值

  • 尽量Xms Xmx设置一样,防止内存抖动

内存分配策略

  • 静态存储:编译时确定每个数据目标在运行时的存储空间需求(无可变数据结构,无嵌套递归)
  • 栈式存储:数据区需求在编译时未知,运行时模块入口前决定
  • 堆式存储:编译时或运行时模块入口都无法确定,动态分配

Java内存模型中堆与栈

  • 联系:引用对象、数组时,栈里定义变量保存堆中目标的首地址

stackandheap

  • 区别:

    1、栈自动释放,堆需要GC

    2、栈空间较堆小

    3、栈产生的内存碎片远小于堆

    4、栈支持静态和动态分配,堆仅支持动态分配

    5、栈效率较高

Hello World实例

hello

hellod

JDK版本问题

  • intern()

intern

  • Copyrights © 2019-2020 Rex