Java - 简述JVM 内存模型

 2019-12-10 16:14  阅读(1018)
文章分类:Java Core

JVM

20191210001679\_1.png

[来源:维基百科]

程序计数器

  • 程序计数器是当前线程执行的字节码的行号指示器;
  • 程序计数器线程私有;
  • 程序计数器是JVM 规范中唯一一个没有任何OutOfMemoryError 的区域;

虚拟机栈

  • 线程私有,生命周期与线程相同;
  • 虚拟机栈描述的是Java 方法执行的内存模型,每个方法在执行时会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。一个方法从调用到执行,就对应着一个栈帧从入栈到出栈的过程。对于一个栈帧来说执行引擎来说,如果一个方法调用链很长,调用其中一个方法,其他好多方法也可能处于执行状态,这时引擎会认为虚拟机栈顶的栈帧才是有效的,这个栈帧被称为当前栈,这个栈帧对应的方法称为当前方法,引擎的所有指令都是针对于当前栈帧进行操作的;
  • 局部变量表,是一组变量值的存储空间,存储单位是slot。若是实例方法,则第0 个slot 存储的是指向所有实例对象的引用,在方法中可以通过this 来访问这个隐含的参数,接着存储的是参数,然后是方法内的局部变量;
  • 操作数栈,方法执行之初为空,执行过程中会有各种字节码指令写入或者弹出值。它不通过索引来访问,而是通过标准的栈操作—压栈和出栈—来访问的,比如,如果某个指令把一个值压入到操作数栈中,稍后另一个指令就可以弹出这个值来使用。所以操作数栈又可以理解为“基于栈的执行引擎”;
  • 动态链接,运行时转为直接引用;静态链接,解析时(符号引用)转化为直接引用;
  • 当线程申请的栈空间大于虚拟机允许的深度时,会出现StackOverFlowError 异常;当虚拟机栈无法申请到足够内存时,会出现OutOfMemoryError 异常;

本地方法栈

同上,为native 方法服务;

  • 线程共享;
  • 用来存储实例对象与数组对象;
  • 由于现在有了逃逸分析技术,也可以将对象分配到栈上;

20191210001679\_2.png

  • “垃圾堆”,Java 堆是GC 的主要区域,主要采用分代回收,有年轻代,老年代;
  • Java 堆,物理上可以不连续,逻辑上要求连续;
  • 内存分配,碰撞指针(要求内存绝对规整,注意线程同步,采用CAS 原理+ 失败重试或者本地线程分配缓冲),空闲列表(内存不规整)。选择哪种分配算法取决于内存是否规整,是否规整取决于采用的GC 算法是否压缩;
  • 对象的访问方法,句柄 + 直接访问;
  • 堆空间不足时抛出 OutOfMemoryError;

方法区

  • 线程共享;
  • 用于存储已经被虚拟机加载的类的类信息,常量,静态变量,编译后的代码,运行时常量池(存储编译器生成的各种字面量与符号引用);
  • class 文件中的常量池在类加载之后就被放入运行时常量池;相比之下,方法区的运行时常量池具有动态性;
  • 常量可以在运行期间通过intern 加入到常量池中;
  • 方法区空间不足时会抛出 OutOfMemoryError;

堆外内存(直接内存)

  1. 直接内存可以减少IO 时的内存复制,零拷贝(不需要堆内存Buffer 拷贝一份到直接内存);
  2. 无gc;

优点:

  • 减少垃圾回收工作,垃圾回收会暂停其他工作(若使用多线程或者时间片方式,根本感觉不到);
  • 加快复制速度,省略掉Buffer Copy To off-heap 过程;

缺点:

  • 难以控制,若内存泄露,排查难度很大;
  • 不适合存储复杂的对象;
点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Java - 简述JVM 内存模型

相关推荐