JVM----Java内存模型

本文详细介绍了Java内存的五个区域:程序计数器、虚拟机栈(包括局部变量表、操作数栈、动态链接和方法返回地址)、本地方法栈、Java堆和方法区(包含运行时常量池)。每个区域的功能和作用,如线程私有、对象创建、动态链接和方法调用等关键概念都得到了阐述,有助于深入理解Java内存管理。
摘要由CSDN通过智能技术生成

目录

1.程序计数器

2.Java 栈(虚拟机栈)

2.1 局部变量表

2.2 操作数栈

2.3 动态链接

2.4 方法返回地址

3.本地方法栈

4. Java堆

5.方法区

5.1 运行时常量池

静态常量池

运行时常量池


JVM内存共被分为五个部分:

1.程序计数器

本质:程序计数器是一块很小的内存空间,它是线程私有的,即每个线程都有属于自己的一个程序计数器。可以作为当前线程的行号指示器。

为什么需要程序计数器

一条线程中会有多条指令,但对于一个处理器,在同一个时刻,在一个确定的时刻都只会执行一条线程中的指令,为了在线程切换后,该线程可以恢复到原本运行的位置,每个线程都需要有一个独立的程序计数器。不同线程之间的程序计数器互不影响。如果执行的是java方法,那么记录的是正在执行的虚拟机字节码指令的地址的地址,如果是native方法,计数器的值为空。

2.Java 栈(虚拟机栈)

也是线程私有的。

每个方法在执行的时候,都会创建一个栈帧,栈帧存储了方法的局部变量,操作数,动态链接,方法返回地址。

线程没调用一个方法,都会把该方法对应的栈帧入栈(虚拟机栈),当该方法运行结束后,该方法的栈帧就会出栈。

2.1 局部变量表

局部变量表是栈帧重要组中部分之一。它主要用于保存函数的参数函数的局部变量对象引用。局部变量表中的变量的作用域是当前调用的函数,当函数调用结束后,局部变量表也会随着栈帧的销毁而消失。由于局部变量表存储函数的参数和局部变量,因此如果函数的局部变量太多,会使得局部变量表膨胀,导致每一次调用会占用更多的栈空间。最终结局就是栈空间内存一定的情况下调用的次数减少。

由于局部变量表所需的内存空间是在编译期间确定的。因此在进入一个方法时,该方法的栈帧中的局部变量表空间是完全已经确定的了,所以在方法运行期间无法通过动态方法改变。

2.2 操作数栈

1.操作数栈的栈深由编译期确定。

2.栈帧刚建立时,操作栈为空。

3.方法运行时,操作栈用于存放JVM从局部变量表中复制的常量或变量。或接收方法返回的结果。

4.操作数栈可用于运算,虚拟机把操作数栈作为它的工作区——大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈。比如,iadd指令就要从操作数栈中弹出两个整数,执行加法运算,其结果又压回到操作数栈中

2.3 动态链接

每个栈帧都保存了 一个 可以指向当前方法所在类的 运行时常量池, 目的是: 当前方法中如果需要调用其他方法的时候, 能够从运行时常量池中找到对应的符号引用, 然后将符号引用转换为直接引用,然后就能直接调用对应方法, 这就是动态链接

2.4 方法返回地址

当一个方法开始执行时,会有两种情况导致方法返回:

1. 方法正常返回(遇到返回指令):方法正常退出时,调用者的PC计数器的值可以作为栈帧的返回地址。让该方法调用结束后,能根据返回地址找到程序调用该方法之前的运行位置。

2.异常返回:当程序发生异常且没有处理时,程序也会返回,这时候的返回地址是要经过异常处理器确定的。

 

3.本地方法栈

本地方法栈和虚拟机栈非常相似,都是线程私有的。区别在于,虚拟机栈是为虚拟机执行Java方法服务的,而本地方法栈是为虚拟机执行Native方法服务的。

Native方法:Native方法并非由Java语言实现,而是由其他语言写的,例如C/C++写好后,让Java程序调用。

4. Java堆

堆是Java内存最大,且管理最复杂的区域。

1. Java堆的目的:存放创建(new)的所有对象。

2.不同于Java栈,Java堆是所有线程共享的。即并不是每个线程都有自己的一个堆空间。因此多线程的时候,也需要同步机制。

Java 堆 = 新生代+老年代。

新生代:存放刚刚创建的新对象。

老年代:由于在堆内存中,会触发GC(垃圾回收),如果有新生代的对象在数次GC中活了下来没被清除,那么就会进入到老年代

新生代 = 伊甸区+s0区+s1区

伊甸区:存放最新创建的对象。当发生GC时,没被清除的对象会移到s0区,然后擦除伊甸区和s1区,然后又发生GC时,会把伊甸区+s0中存活的对象移到s1区,然后擦除伊甸区和s0区,循环往复,每次存活下来的对象的年龄都会+1,年龄超过一定阈值,就会进入老年代。

5.方法区

方法区和堆都是线程共享的内存区域,为了和堆区分,方法区又叫非堆。

方法区用于存储被虚拟机加载的 类信息、常量、静态变量。如用 static 修饰的变量会被加载到方法区中。

5.1 运行时常量池

运行时常量池是方法区的其中一个区域。

Java的常量池分两种形态:静态常量池和运行时常量池

静态常量池

静态常量池即*.class文件中的常量池,里面包括 字符串字面量、类、方法信息。这种常量池一般存放两大类常量:字面量符号引用量

字面量:如文本字符串,声明final的常量值。

符号引用量:类和接口的全限定名字段名称和描述符方法名称和描述符

运行时常量池

运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。

运行时常量池相对于CLass文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入CLass文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值