0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

程序员眼里的内存(中)

jf_78858299 来源:码农的荒岛求生 作者:码农的荒岛求生 2023-02-24 14:09 次阅读

本节是操作系统系列教程的第三篇文章,属于操作系统第一章即基础篇,在真正开始操作系统相关章节前在这一部分回顾一些重要的主题,以下是目录,由于本文篇幅较多因此会按上篇、中篇、下篇三次发布,目录中黑体为本篇内容。


什么是内存

C/C++内存模型

**堆区与栈区的本质

**

**JavaPython等内存模型

**

**Java内存模型

**

**Jave中的堆区与栈区是如何实现的

**

Python内存模型

指针与引用

进程的内存模型

幻想大师-操作系统

总结


堆与栈的本质是什么

编程语言中,堆区和栈区本质上都是内存,因此二者在本质上没有任何区别,只不过这两块内存的使用方式是不一样的。

在数据结构与算法中,我们也有堆和栈的概念,但那里指的不是内存,而是两种数据结构。

你可能会想,我们为什么要费尽心力的提出堆和栈这两个概念呢?之所以需要区分两种内存用法,根源在于: 内存是有限的

如果计算机内存是无限的,那么我们根本就不用这么麻烦的给内存划分两个区域,在其中的一个区域中这样使用内存,另一区域那样使用内存,这些都是不需要的。即使在今天PC内存普遍都在8G、16G,这依然是不够的,因此我们需要合理的来安排内存的使用,堆和栈就是为达到这一目的而采用的技术。

你会发现栈其实是一种非常巧妙的内存使用方法。函数调用完成后,函数运行过程中占用的内存就会被释放掉,这样,只要程序员代码写的合理(栈帧不至于过大),那我们程序就可以一直运行下去,而不会出现内存不足的现象。程序员在栈区不需要担心内存分配释放问题,因为这一切都是自动进行的。而如果程序员想自己控制内存,那么可以选择在堆上进行内存分配。因此这里提供了两种选择,一种是“自动的”,一种是“手动的”,目的都是在合理使用内存的同时提供给程序员最大的灵活性。

堆和栈是计算机科学中很优秀的设计思想,这种设计思想充分的体现了计算机如何合理且灵活的使用有限资源。

堆区和栈区对C/C++程序员来说就是实实在在的内存,而对于Java、Python等语言的程序员来说又该如何理解内存呢?

Java、Python等内存模型

当Java、Python等语言的程序在执行时其解释器的内存布局同样如下图所示,我们之前讲过,解释器也是一个C/C++程序,因此这里的代码段包含的是解释器的实现代码而不是Java、Python等代码,这一点大家一定要注意。

"C/C++程序员面对的是实实在在的物理内存,Java、Python等程序面对的是解释器。"

C/C++分配内存是直接在物理内存中进行的,而Java、Python等程序是将内存分配请求交给解释器,解释器再去物理内存上进行分配。希望大家务必理解这一点。

Java、Python等程序员是看不到如下图所示的内存布局的,因为这一切都是解释器才能看到的,解释器对Java、Python等程序员屏蔽了这些。Java、Python等程序员也无需关心解释器的内存布局。

Java、Python等程序的一大优点就是内存的自动化管理,而C/C++程序员需要自己来管理从堆上分配的内存。内存管理这一项工作在Java、Python等程序中被解释器接管了,解释器的这项功能被称为“垃圾回收器”。

在非C/C++语言中,我们来看两个有代表性的语言,首先我们看一下Java。

Java内存模型

Java的内存模型中同样有栈和堆这样的概念,如下图所示,在Java函数中我们定义的内置数据类型比如int a = 0,是直接存放在栈上的,引用类型,也就是用new关键字定义的变量是分配在堆上的。和C/C++一样,每个Java函数在执行时都有自己的栈帧。随着函数的调用,栈不断的扩大。当函数调用完毕后栈帧被回收,在堆上分配的变量依然可以被后续函数使用。Java程序员无需像C/C++程序员一样需要关心内存回收的问题,这一切都是Java的解释器JVM来管理的。

在用法上Java中的堆和栈和C/C++是一样的,只不过Java程序员无需关心内存的释放问题。但是好奇的同学可能会问,C/C++中的堆和栈我已经清楚了,因为C/C++程序运行时在内存中的样子已经在《C/C++内存模型》这一小节中详细的讲述了,那么Java中的堆和栈在内存中是什么样子的呢,就是和上图一样吗?要回答这个问题,就要涉及到Java中的堆和栈是如何实现的。

Java中的堆和栈是如何实现的

如果你自己设计过一门语言的话,你应该会很清楚这个问题。

我们先回答上一节中提到的问题,那就是Java中的堆和栈就是如上图所示的那样吗?是这样的,作为Java程序员在写代码时脑海里有上面这张图基本上就够用了。但是,Java中的堆和栈不同于C/C++当中的堆和栈。

我们已经知道Java中的内存管理其实是解释器JVM来搞定的,作为C/C++程序,JVM的内存布局就如下图所示。

一般情况下,当JVM运行一个Java函数时需要在堆上创建出Java函数的栈帧,然后把这些栈帧放入栈中(这里的栈指的是具有先进后出性质的数据结构)。希望大家不要被这句话绕晕,这里出现了两个“栈”,但是含义完全不同。

  • Java栈帧:指的是上图中我们看到的栈。

  • 栈帧放入到栈:我们在数据结构课程中都学过栈,栈有push和pop两种操作,把栈帧放入栈指的是把栈帧push到JVM所持有的栈这种数据结构当中,以此来模拟C/C++程序执行过程中函数栈帧先进后出的这种性质,当一个Java函数被执行完毕后,JVM pop掉该函数的栈帧。

    如果你想在代码级别来理解这个过程,大体上可以参考下面的代码,注意JVM是C/C++程序,这里的代码是一个极其简单的描述。你可以看到如何组织栈帧完全是JVM设计者来决定的,只要栈帧具备先进后出的性质就可以。

void RunJavaFunction(JVM* jvm, string javaFunction) {


    // 在堆上申请一块空间,用于存放java栈帧
    stackFrame* frame = (stackFrame*) malloc(sizeof(stackFrame));

    // 把要使用的栈帧push到JVM的函数调用栈中
    jvm->stack->push(frame);

    // 在申请的栈帧上执行Java函数
    run(javaFunction, frame);

    // 执行完毕后pop掉该函数栈帧
    jvm->stack->pop();
}

JVM会在自己的堆中为用new修饰的对象创建内存,这里的堆就是如上图所示的堆,是可以要记住JVM是一个C/C++程序,JVM看到的堆才是如上图所示的那样。所以你会发现,一般情况下, Java中的栈和Java对象都是JVM在自己的堆上分配出来的 ,这就是Java中堆和栈是如何实现的。

在讲解完Java的内存模型后,我们来看一下Python的。

Python内存模型

Python的内存模型和Java其实是类似的,Java程序员脑海中的那张图同样适用于Python程序员。

Python语言中的解释器比较多,比如CPython,PyPy等,在这里我们以Python默认的解释器CPython为例来说明,我们已经知道了解释器其实也是一个C程序,CPython也不例外,下图左侧就是我们已经熟悉的C/C++内存布局,我们把堆区放大,如下图右侧所示。我们可以看到Python的解释器把自己的堆区划分成了两部分,分别是Object-specific memory区域,以及Python core区域:

Object-specific memory这个区域专门用来存放PyObject。你也许已经知道了,Python中所有的数据类型比如int,dict,str等都是一个对象,叫做PyObject。当我们在Python中创建一个变量比如dict时,CPython就会在堆区的上半部分(Object-specific memory)中分配一块内存,创建一个PyObject,这个PyObject用来存放我们的dict。

Python core:所有非PyObject的内存请求都在这里分配的。

所以你会发现,Python中所有的内存同样是解释器在自己的堆上分配的。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2957

    浏览量

    104544
  • 堆栈
    +关注

    关注

    0

    文章

    182

    浏览量

    19731
  • python
    +关注

    关注

    56

    文章

    4782

    浏览量

    84449
收藏 人收藏

    评论

    相关推荐

    程序员需要学什么,微软资深程序员学习手册面试宝典资料

    程序员是现在比较吃香的工作。程序员工资高还不需要和复杂的社会打交道。那么怎么成为一名程序员?当程序员需要学什么?
    发表于 03-22 11:54 30次下载

    “菜鸟”程序员和“大神”程序员到底有什么区别

    现在社会上有很多程序员,那您是否可想过程序员为什么会有不同的水平?你又是哪一类的程序员?“菜鸟”程序员和“大神”程序员差在哪里?
    的头像 发表于 05-14 08:48 3697次阅读

    这可能就是程序员最大的悲哀

    这个繁荣的行业,只要你自己不水,可以衣食无忧,努努力还能buffer加成,成为别人眼里很酷的那种人,没多少行业如程序员起薪高,也没多少行业如程序员涨薪快,没多少行业如程序员这般智力密集
    的头像 发表于 12-07 15:47 1212次阅读

    程序员如何定义

    当了几年的程序员了,一直都在想一个问题,什么是程序员程序员应该做好那些事情,什么样的程序员是有素质的程序员?什么样的
    的头像 发表于 12-18 14:15 2597次阅读

    菜鸟程序员和大神程序员的差距

    刚刚走出就业的程序员,技术是刚刚起步的基点。那下面我们就聊一聊有关技术的东西。首先请您先想想这几个问题。现在社会上有很多程序员,CSDN就是我们程序员的家,那您是否可想过程序员为什么会
    的头像 发表于 06-03 15:56 2511次阅读

    什么是程序员

    当了几年的程序员了,一直都在想一个问题,什么是程序员程序员应该做好那些事情,什么样的程序员是有素质的程序员?什么样的
    的头像 发表于 06-04 16:21 8916次阅读

    程序员的未来

    程序员出路在何方程序员 创业如果你是程序员,也想创业,看看我说的。
    的头像 发表于 06-12 17:29 2927次阅读

    为什么要成为高级程序员

    程序员到高级程序员的职业生涯要经历以下几个阶段:初级程序员、中级程序员、最后是高级程序员
    的头像 发表于 07-11 16:51 2412次阅读

    普通程序员和高级程序员有哪些区别

    从工作的方面来说,普通程序员和高级程序员一般有下面几个区别:
    的头像 发表于 09-08 10:47 3746次阅读

    如何定义程序员

    多年以来,黑程序员一直是一项广大人民群众喜闻乐见的娱乐活动,我们不仅黑程序员程序员也喜欢自黑,如此一来,大家好像都觉得黑程序员是一项天经地义的事情了,然而事实上,的确是的。
    的头像 发表于 10-28 17:05 2706次阅读

    JAVA程序员和C程序员有什么区别

    1、知道JAVA程序员和C程序员的差别吗?食堂里,吃完饭就走的是JAVA程序员,吃完饭还要自己收拾的那就是是C程序员。至于为什么会这样,大家都明白(因为JAVA自带垃圾回收机制,C需要
    的头像 发表于 11-03 11:25 4295次阅读

    优秀程序员与糟糕程序员的变现差异

    软件蚕食一切,未来属于程序员。所以人人都想当程序员。但是并不是每个人都能当好程序员。在你做出决定前还是先看看自己能不能当好程序员吧。
    的头像 发表于 11-07 16:14 3041次阅读

    程序员最大的失败是什么

    程序员最大的失败就是认为自己是好的程序员
    的头像 发表于 11-18 16:26 3200次阅读

    程序员的类型

    今天来聊个有趣的话题,你是什么类型的程序员? 在学校里或在公司里,你是不是接触过不少其他的程序员,有没有发现,虽然同属程序员科, 但也有众多的不同。 今天我就来给程序员分个类,看看你是
    的头像 发表于 11-28 16:39 4671次阅读

    每个程序员都应该知道的内存

    随着CPU内核变得更快和更多,大多数程序的限制因素是现在,也将是一段时间,内存访问。硬件设计师已经想出了更复杂的内存处理和加速技术(如CPU缓存),但是如果没有程序员的帮助,这些功能就
    发表于 11-23 16:55 0次下载