(一)JVM之内存模型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36520235/article/details/82225617

先看一下整个JVM中的大体知识体系

感谢大佬的图:https://www.cnblogs.com/smyhvae/p/4810168.html

这里写图片描述
这里写图片描述

JVM模型图

这里写图片描述
首先整体来看,在运行每个我们所构建的类的时候,包括类中的方法、变量、静态方法、静态常量、实例对象的时候都是在不同的区域储存,然后内部用也用到了指针来实现,只是表面上我们看不到而已。

1、JVM虚拟机栈

在JVM虚拟机中每个线程都是私有的。每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至完成的过程,都对应一个栈帧从入栈到出栈的过程。

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)
这里写图片描述

2、程序计数器

你可以这样理解,因为每个线程都是私有的,每个线程一次只能执行一个方法,这个程序计数器可以记录当前线程执行到哪条指令了(因为如果多个线程同时进行的话,有时候会出现当前的线程被挂起的情况,去执行其他线程,此时这个线程如果再次被唤醒的时候,cpu并不知道上次挂起之前执行到那个方法了,这个时候程序计数器就起到作用了)。

Java虚拟机允许多个线程同时执行指令。如果有多个线程正在执行指令,那么每个线程都会有一个程序计数器,它是线程私有的。在任意时刻,一个线程只允许执行一个方法的代码。每当执行到一条Java方法的指令时,程序计数器保存当前执行字节码的地址;若执行的为native方法,则PC的值为undefined。堆

3、本地方法栈

本地方法栈和Java虚拟机栈的作用相似,Java虚拟机栈执行的是字节码,而本地方法栈执行的是native方法。本地方法栈使用传统的栈(C Stack)来支持native方法。在HotSpot JVM中Java虚拟机栈和本地方法栈合二为一。

4、 堆区

  • 在JDK1.8之前,堆区中不仅有 新生代、年老代和永久代,且比例为8:1:1,但是在JDK1.8之后,永久代改为元空间。新生代采用的是回收算法,默认连续复制15次就会把新生代移动到年老代
  • 而且堆区不仅是jvm中占据最大的空间,而且还是被各个线程所共享的一部分区域。该区域存放了大部分的对象实例级数组(但并不是全部的对象实例都在堆中)
  • 其大小通过-Xms(最小值)和-Xmx(最大值)参数设置(最大最小值都要小于1G,因为堆内存才只有1G),前者为启动时申请的最小内存,默认为操作系统物理内存的1/64,后者为JVM可申请的最大内存,默认为物理内存的1/4,默认当空余堆内存小于40%时,JVM会增大堆内存到-Xmx指定的大小,可通过-XX:MinHeapFreeRation=来指定这个比列;当空余堆内存大于70%时,JVM会减小堆内存的大小到-Xms指定的大小,可通过XX:MaxHeapFreeRation=来指定这个比列,当然为了避免在运行时频繁调整Heap的大小,通常-Xms与-Xmx的值设成一样

这里写图片描述

5、方法区

  • 方法区也称”永久代”,它用于存储虚拟机加载的类信息、常量、静态变量、是各个线程共享的内存区域。默认最小值为16MB,最大值为64MB(64位JVM由于指针膨胀,默认是85M),可以通过-XX:PermSize 和 -XX:MaxPermSize 参数限制方法区的大小。它是一片连续的堆空间,永久代的垃圾收集是和老年代(old generation)捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。不过,一个明显的问题是,当JVM加载的类信息容量超过了参数-XX:MaxPermSize设定的值时,应用将会报OOM的错误。参数是通过-XX:PermSize和-XX:MaxPermSize来设定的
    • 运行时常量池(Runtime Constant Pool):是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种符号引用,这部分内容将在类加载后放到方法区的运行时常量池中。

6、直接内存

  • 直接内存并不是虚拟机内存的一部分,也不是Java虚拟机规范中定义的内存区域。jdk1.4中新加入的NIO,引入了通道与缓冲区的IO方式,它可以调用Native方法直接分配堆外内存,这个堆外内存就是本机内存,不会影响到堆内存的大小.

猜你喜欢

转载自blog.csdn.net/qq_36520235/article/details/82225617