JVM内存结构

​​JVM是什么

1.程序计数器 PC Register

每个线程都有一个程序计算器,就是一个指针,指向方法区中的方法字节码(下一个将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。

2.本地方法栈 Native Method Stack

Native Method Stack中登记native方法,在Execution Engine执行时加载native libraies

本地方法栈与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务

3.虚拟机栈 JVM Stack

编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(引用指针,并非对象本身)

栈是java 方法执行的内存模型:

每个方法被执行的时候 都会创建一个“栈帧”用于存储局部变量表(包括参数)、操作栈、方法出口等信息。

每个方法被调用到执行完的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

栈的生命期是跟随线程的生命期,线程创建时创建,线程结束栈内存也就释放,是线程私有的。

4.方法区 Method Area

用于存储虚拟机加载的:静态变量+常量+类信息+运行时常量池 (类信息:类的版本、字段、方法、接口、构造函数等描述信息 )

默认最小值为16MB,最大值为64MB,可以通过-XX:PermSize 和 -XX:MaxPermSize 参数限制方法区的大小

5.堆 Java Heap

所有的对象实例以及数组都要在堆上分配,此内存区域的唯一目的就是存放对象实例

堆是Java 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建

堆是理解Java GC机制最重要的区域,没有之一

结构:新生代(Eden区+2个Survivor区) 老年代 永久代(HotSpot有)

新生代:新创建的对象——>Eden区

GC之后,存活的对象由Eden区 Survivor区0进入Survivor区1

再次GC,存活的对象由Eden区 Survivor区1进入Survivor区0

老年代:对象如果在新生代存活了足够长的时间而没有被清理掉(即在几次Young GC后存活了下来),则会被复制到老年代

如果新创建对象比较大(比如长字符串或大数组),新生代空间不足,则大对象会直接分配到老年代上(大对象可能触发提前GC,应少用,更应避免使用短命的大对象)

老年代的空间一般比新生代大,能存放更多的对象,在老年代上发生的GC次数也比年轻代少

永久代:可以简单理解为方法区(本质上两者并不等价)

Jdk1.6及之前:运行时常量池逻辑包含字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代

Jdk1.7:字符串常量池被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代

Jdk1.8及之后:在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。同时在 jdk 1.8中移除整个永久代,取而代之的是一个叫元空间(Metaspace)的区域

6.直接内存 Direct Memor

直接内存并不是JVM管理的内存,可以这样理解,直接内存,就是JVM以外的机器内存,比如,你有4G的内存,JVM占用了1G,则其余的3G就是直接内存

JDK中有一种基于通道(Channel)和缓冲区(Buffer)的内存分配方式,将由C语言实现的native函数库分配在直接内存中,用存储在JVM堆中的DirectByteBuffer来引用

由于直接内存收到本机器内存的限制,所以也可能出现OutOfMemoryError的异常。

相关文章:

  • 2021-05-04
  • 2021-10-26
  • 2021-08-27
  • 2021-07-09
  • 2021-11-21
  • 2021-11-27
  • 2021-11-07
猜你喜欢
  • 2021-04-21
  • 2021-11-03
  • 2021-08-30
  • 2021-09-16
相关资源
相似解决方案