关于JVM和OS中的栈帧的区别和内存浅析

关于JVM和OS中的栈帧的区别和内存浅析


刚看了黑马JVM中的栈帧的讲解,感觉和自己理解的栈帧有一定出入,查询资料研究了一下发现的确有天壤之别,可惜黑马并没有讲。

故写下这篇文章巩固一下,


OS的栈帧:

​ OS的栈帧会在调用一个函数时,分配一段内存,存入函数调用的局部变量、参数、返回地址等信息进去,列如下面这一段C程序:

c 复制代码
#include<stdio.h>
int add1(int a, int b) {
    return add2(a,b);
}
int add2(int a, int b) {
    return a + b;
}
void main(){
    add1(1,2);
}

首先,程序会把这个代码从上开始执行

当执行到main函数时,会在内存上分配如下:

这里的返回地址 指的是进入这个函数的指令地址 ,也就是**程序计数器(PC)**寄存器,里面保存的是下一条被执行的语句的位置,因为你调用了函数,PC就得移到函数代码的地方,为了执行完函数能回到原代码,就会在函数的栈帧里面保存返回地址,这样执行完函数就会通过返回地址返回到原本的地方继续执行。


接着进入add1,add2就显而易见:

栈帧是用栈来存储的,遵循先进先出,程序只能操作最顶上的栈帧!

每当执行到一个函数,就会创建一个栈帧,存储变量和对应返回地址,当执行完毕后,栈帧会被回收

这也就是为什么函数需要预先声明要用的变量的原因,计算机需要知道你的大小和所需来为你分配合适的栈帧。

你只能使用你栈帧里面的数据,一旦越界访问就会报错

总的来说,栈帧在OS里面会保存函数执行的一切信息,包括变量对象,返回地址,各种参数

但对于全局变量,以及类似于C++中的vector这种动态申请空间的,栈帧里面只会存对其的内存地址 (可以理解为指针),实际上其处于另一片区域中,具体看程序内存分配的总体图

这也被称为内存五大区:栈区 -> 堆区 -> 全局静态区 -> 常量区 -> 代码区

各个区解释如下:

内核区,是OS的系统文件或其他文件,反正不应该被程序触碰到,接触到就会报错

栈区,也就是上文提到的栈帧存放处,从上到下存储!

堆区, 存储程序手动分配的空间,也就是new,vector此类,读取较慢

全局区,存储全局变量

常量区,存储常量

代码区,存储原代码

保留区,4k大小,不作操作

对于32位计算机,全部部分加起来一共有4G

栈区是从上到下使用,堆区是从下到上

缓存区用来作缓冲,双方都能使用

一旦冲突,便会发生溢出错误

以上是OS中栈帧的简单解释


JVM的栈帧:

Java这种高级语言的栈帧和OS中的栈帧是两个东西

本质是JVM抽象出来的,和OS的栈帧没有关系

但是结构差不多,可以说较为相似

(来自小林coding)

这里的本地方法指的是native方法,不是由java实现的方法!是由C语言实现的来对底层进行交互的方法!

那本地方法栈完全可以套用前文

对于Java虚拟机栈帧,仅和OS栈帧有一点区别:其不会把数据对象存储在栈帧中,而是只会存储一个引用!

对象本身是存在堆中的,和OS的栈帧不同

对于static的变量和方法,static方法在内存上的存储方式其实和非static没有多大区别,都是同样的创建栈帧调用,只是会少一个this指针,绑定在static中,不能实现多态,可以直接调用

static变量则会直接保存在方法区,不像非staic变量存储在堆里面

堆是 JVM 中最大的一块内存区域,被所有线程共享,在虚拟机启动时创建,用于存放对象实例。

程序计数器(PC)效果和OS相同,都是存储下一条该执行的语句的地址

元空间用于存储已被虚拟机加载的类信息、常量、静态变量等数据

直接内存不属于 JVM 运行时数据区的一部分,通过 NIO 类引入,是一种堆外内存,可以显著提高 I/O 性能。


总的来说,JVM和OS的内存管理结构上其实并没有很大区别,只是需要注意,JVM的内存是对OS的内存的一次抽象,是间接实现的,不是像OS那样通过汇编直接实现.

所以说既然不是直接实现的,那就必然会对性能有影响,这也是java性能不如C的原因之一

栈帧也是对OS的栈帧的模拟,区别在于不会把所有对象都放在栈帧中,而是放在堆中,这是和OS的区别

相关推荐
ChinaRainbowSea6 分钟前
补充:问题:CORS ,前后端访问跨域问题
java·spring boot·后端·spring
KiddoStone16 分钟前
多实例schedule job同步数据流的数据一致性设计和实现方案
java
岁忧37 分钟前
(LeetCode 每日一题) 1865. 找出和为指定值的下标对 (哈希表)
java·c++·算法·leetcode·go·散列表
YuTaoShao40 分钟前
【LeetCode 热题 100】240. 搜索二维矩阵 II——排除法
java·算法·leetcode
考虑考虑2 小时前
JDK9中的dropWhile
java·后端·java ee
想躺平的咸鱼干2 小时前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程
hqxstudying2 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
·云扬·2 小时前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言
Bug退退退1233 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
小皮侠3 小时前
nginx的使用
java·运维·服务器·前端·git·nginx·github