jvm内存模型

587 阅读4分钟

     Java的内存管理采用[自动内存管理]机制,因为这个自动管理机制,Java程序员就不需要去写释放内存的代码,而且不容易出现内存泄漏问题。但是由于内存的申请和释放都交给了Java虚拟机,一旦出现内存泄漏和溢出问题时,在不了解Java虚拟机内存结构和自动管理机制的情况下,就很难排查问题的所在。所以需要我们去了解内存模型才能对他进行优化。

1、jvm内存模型

截屏2021-06-26 15.29.34.png

1.1线程私有

  1. 程序计数器 程序计数器(Program Counter Register)是一块较小的内存空间,它可以是看作当前线程所执行的字节码的行号指示器。简单的说,为线程私有记录了当前线程的执行字节码指令的位置,在线程上下文切换中能够接着执行上次执行的位置。

  2. jvm虚拟机栈 JVM必须有一块区域是来保存每个方法内的局部变量等数据的,这个区域就是Java虚拟机栈 每个线程都有自己的Java虚拟机栈,比如这里的main线程就会有自己的一个Java虚拟机栈,用来存放自己执行的那些方法的局部变量。 如果线程执行了一个方法,就会对这个方法调用创建对应的一个栈帧,栈帧里就有这个方法的局部变量表 、操作数栈、动态链接、方法出口等东西,

  3. 本地方法栈 本地方法栈和虚拟机栈所发挥的作用是很相似的,它们之间的区别不过是 虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。Sun HotSpot 直接就把本地方法栈和虚拟机栈合二为一。本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。

1.2线程共享

  1. 方法区 方法区在JVM中也是一个非常重要的区域,它与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。方法区是堆的一个逻辑部分,为了区分Java堆,它还有一个别名Non-Heap(非堆)。相对而言,GC对于这个区域的收集是很少出现的。当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。 在Java 7及之前版本,我们也习惯称方法区它为“永久代”(Permanent Generation),更确切来说,应该是“HotSpot使用永久代实现了方法区”!

  2. 常量池

  • 运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池( Constant pool table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入运行时常量池中存放。
  • 运行时常量池相对于class文件常量池的另外一个特性是具备动态性,java语言并不要求常量一定只有编译器才产生,也就是并非预置入class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中。

3、堆

  • 堆被所有线程共享,在虚拟机启动时创建,用来存放对象实例,几乎所有的对象实例都在这里分配内存。
  • 对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。
  • Java堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC堆”。如果从内存回收的角度看,由于现在收集器基本都是采用的分代收集算法,所以Java堆中还可以细分为:新生代和老年代;新生代又有Eden空间、From Survivor空间、To Survivor空间三部分。
  • Java 堆不需要连续内存,并且可以通过动态增加其内存,增加失败会抛出 OutOfMemoryError 异常。