JVM修炼之路【7】-JVM内存模型

java虚拟机管理这块内存,所以我们也叫运行时数据区域

很多介绍jvm的资料中 上来就说内存模型 这会让新手比较懵逼,所以我的博客专栏里面:

先说 java程序执行的整个过程, 再说编译后的字节码文件,字节码文件的加载也就是类加载过程, 最后加载到jvm之后 发生了什么
jvm怎么处理 怎么存储 怎么运行这些加载进来的字节码文件, 这时候才引出了 jvm的内存模型

总览

在这里插入图片描述
这里按线程是否共享来分类,所谓线程不共享就是每个线程里面都会配一套 程序计数器 栈, 互相不干涉。
而方法区和堆是线程所有共享 意味着只有一个(这里注意堆是实际概念 方法区是一个虚拟概念)

程序计数器

在这里插入图片描述


注意:程序计数器记录字节码的内存地址,这个内存地址是怎么来的?
在前几篇中 字节码通过 .class文件 由类加载器 加载到方法区中(在解析那一步 将引用地址替换成堆内存里面的内存地址)
如下:
在这里插入图片描述

字节码中每一行都用地址标识,程序计数器就像是一个地址指示器,告诉执行程序 下一行去执行哪里。

java虚拟机的多线程是线程轮流切换 并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,处理器只会执行一条线程中的指令。 所以 为了线程切换后能恢复到正常位置 每个线程都需要一个独立的程序计数器,这就是为什么 程序计数器不能像堆 方法区那样 多线程共享

这篇博客的读者 一定要理解透这一点。

最后问题来了 既然这样 程序计时器 会内存溢出吗? 不会 因为字节码文件中指令的数量 是固定的。


java虚拟机栈

在这里插入图片描述

栈这个数据结构是个单向的,你可以把它想象成一个竖着的一边开口的箱子。它是先进后出。

一个栈就对应一个线程的运行。

看上图的Demo: main 调用a , a调用b ,b调用c。

那么在栈里面就是 mian 先入栈,后面依次是 a b c 入栈, 然后c先被执行完 执行完之后 c 出栈,后面 b a main 依次出栈。

这个时候新手可能会蒙蔽一下:a 调用 b 不是a先执行吗? 这里要注意,执行b方法 这个过程是 执行a方法中的一部分,a调用b的时候a开始执行 但是没执行完 b执行完之后 还在a的方法里面 再往下走 a才执行完


上面就是方法执行过程中栈的逻辑,每执行一个方法 就是一个栈内部栈帧入栈和出栈的过程。

然后我们来学习一下 java虚拟机栈内部一个栈帧由哪些组成:

局部变量表
局部变量表里面存放着,运行过程中所有的局部变量,我们知道 每执行一个方法就会创建一个栈帧,那么这个方法里面的局部变量自然要存入栈帧里面,所以在栈帧里面就创建一个局部变量表来专门存储这些局部变量,方法结束 栈帧也就出栈结束了。

顺便说一句 一个方法一般都会有 方法参数,参数变量也会存在这里。

操作数栈
操作数栈你可以把它理解成一个临时存放数据的区域,虚拟机在执行字节码指令的时候 需要把一些数据临时存起来备用,
比如我们交换 a和 b的值 在计算机里面 你需要把a的值先临时放到某个地方 然后把b的值给a 再从那个临时存放点 把a的值拿出来给b
这种执行指令时留的一点余地 就是操作数栈的作用

(还记得之前讲过的 那个 int i=0 i=i++ 的那个例子吗, 在那个例子中就说到了 局部变量表 存方法中的 局部变量 i, 操作数栈临时存储i的值比如 0 或者 1)

帧数据
帧数据不同的虚拟机有差异
这里面最主要的需要了解的两个:

  • 动态链接:在字节码指令中,一个类可能需要调用其他类的方法或者属性,这时候就需要用动态链接 用一个映射把其他类的方法信息引进来
  • 方法出口:上面说过一个方法执行完 就是一个栈弹出的过程,但是弹出以后 虚拟机会疑惑 此时线程执行到哪里了?? 这里就需要在方法出口中记录方法执行完后 下一步的位置信息。

本地方法栈

本地方法栈和虚拟机栈发挥的作用很相似,只不过虚拟栈针对的是java代码编译后的字节码

本地方法栈针对的是 虚拟机本身的底层已经编写好的 native 方法。

还记得之前讲过 jvm的组成里面 有个本地接口吗

然后熟悉的问题又出现了 刚才说了 程序计数器是不可能内存溢出的 那栈会不会溢出呢

答案是会

我们再看这张图片 每一个线程分配的栈大小的是有限的 在这个栈中 现在有abc三个方法 假设这个方法的数量 一直往往上加 c还有d d里面还有e 总有一天 就会造成栈内存溢出
在这里插入图片描述
我们常说的递归, 万一你不小心写成了死循环 无限递归下去 就吧栈挤爆了


堆是jvm里面内存最大的一块 线程共享区域。

首先我们要关注三个重要的值
在这里插入图片描述

这三个值 我们平时怎么查呢 这时候又要用到之前说的 神器 arthas

在这里插入图片描述
在这里插入图片描述
然后 重点来了 怎么去设置

相信很多的java程序员 在配置java的时候 遇到过这两个参数

-XMSsize 其实这个就是total

-XMXsize 这个就是max

是不是很眼熟

最后注意一点

在这里插入图片描述

最后 经典问题又来了, 刚才说了 程序计数器不会溢出 栈可能会溢出

那堆会不会内存溢出?

答案是肯定的 创建的对象都放在堆上面, 那你不断的无限循环创建对象 肯定就OOM了


方法区

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
这里还有一个小问题 静态变量存在哪里呢:

在这里插入图片描述

还记得我们之前讲过 字节码文件把类的元信息存到 方法区的时候 在堆上面会创建一个对应的 class对象 反射就是通过这个对象去获取的

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值