2.jvm内存管理

2021-07-13  本文已影响0人  段段小胖砸

一、整体架构

五个部分


image.png

线程私有:右侧部分,虚拟机栈、本地方法栈、程序计数器
线程共享:左侧部分,堆,方法区

五个模块:类装载子系统、运行时数据区、执行引擎、本地方法接口、垃圾收集模块


image.png

(class字节码文件— 加载(选择类加载器)—连接—初始化)

二、运行时内存

2.1程序计数器

线程私有的,记录字节码行号(类似寄存器的程序计数器)。可以告诉我们每一个线程执行到了哪一个位置。
pc寄存器所在的线程失去执行权时会记录下一条指令对应的编号,在线程重新获取执行权时执行。

2.2虚拟机栈

线程私有,内存连续。每调用一个方法都是入栈。虚拟机栈包含栈帧(方法A),每个方法压栈之后会有一个新的栈帧,栈帧内包含局部变量表、操作栈,动态链接、方法返回地址,虚拟机栈中有很多栈帧(方法)。

public class StackDemo2 { 
    public static void main(String[] args) { 
        int i = 1; 
        int j = 2; 
        int z = i + j; 
    }
  }

如上,i,j,z和它们的值一开始存在局部变量表中,当程序计数器指向i=1这行的时候,将1从局部变量表复制到操作数栈中,接着指向j=2,将2复制到操作数栈,再然后指向j+i,得到结果3,将结果3放入操组数栈并且返回保存到局部变量表

2.3本地方法栈

线程私有,为native方法提供服务。在虚拟机栈调用本地方法的时候提供调用服务

2.4堆

线程共享,内存不连续,包含新生代和老年代。
堆空间大设置:最大:Xmx20m 最小:Xms

2.5元空间

1.8开始,元空间取代了方法区,位于本地内存中而不是jvm虚拟机中。
元空间中存放了原本存在于方法区中的类的元信息,而方法区中的静态变量和常量池并入堆中。
元空间好处:

区别
元空间metaspace可以在运行时扩展。
元空间metaspace是本机内存的一部分,而permGen是堆的一部分。

2.6方法区

线程共享,被虚拟机栈加载过的数据保存在方法区,比如类的信息、常量,静态变量。包含永久代。
去除后,方法区的内容被瓜分:(类静态变量、字符串常量池好像在jdk7就已经转移到堆了)

Java7及以前版本的Hotspot中方法区位于永久代中。同时,永久代和堆是相互隔离的,但它们使用的物理内存是连续的。

2.7运行时常量池

运行时常量池vs常量池
理解为字节码中的常量池 Constant pool 只是文件信息,它想要执行就必须加载到内存中。而Java程序是靠
JVM,更具体的来说是JVM的执行引擎来解释执行的。执行引擎在运行时常量池中取数据,被加载的字节码常量池
中的信息是放到了方法区的运行时常量池中。
它们不是一个概念,存放的位置是不同的。一个在字节码文件中,一个在方法区中。

2.8直接内存

在JDK 1.4中新加入了NIO(New Input/Output) 类, 引入了一种基于通道(Channel) 与缓冲区 (Buwer) 的I/O方式, 它可以使用Native函数库直接分配堆外内存, 然后通过一个存储在Java堆里面的 DirectByteBuwer对象作为这块内存的引用进行操作。 这样能在一些场景中显著提高性能, 因为避免了 在Java堆和Native堆中来回复制数据。

类信息:





反射获取method、field、interface等都是从private transient volatile SoftReference<Class.ReflectionData<T>> reflectionData; 这个变量中获取,在java.lang.Class中被声明为类变量。

字符串常量池(String Pool)

静态常量池(class文件常量池)

运行时常量池

在JDK1.8中,使用元空间代替永久代来实现方法区,但是方法区并没有改变,变动的只是方法区中内容的物理存放位置。正如上面所说,类型信息(元数据信息)等其他信息被移动到了元空间中;但是运行时常量池和字符串常量池被移动到了堆中。但是不论它们物理上如何存放,逻辑上还是属于方法区的。

元空间的本质和永久代类似,都是对JVM规范中方法区的实现。

上一篇下一篇

猜你喜欢

热点阅读