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

    文章

    2916

    浏览量

    103356
  • 堆栈
    +关注

    关注

    0

    文章

    173

    浏览量

    19618
  • python
    +关注

    关注

    53

    文章

    4701

    浏览量

    83703
收藏 人收藏

    评论

    相关推荐

    成为优秀程序员的条件(下)

    能够在每一次研发过程中都考虑到这些问题,那么程序员就不会在重复性的工作耽误太多时间,就会有更多时间和精力投入到创新的代码工作中去。 9 韧性和毅力。高手们并不是天才,他们是在无数个日日夜夜磨练
    发表于 08-22 11:52

    【PDF】《疯狂的程序员

    `内容简介 · · · · · ·   本书描写了绝影等程序员的成长之路,分为大学、工作、创业三部分。作者笔下以绝影、BOSS liu、Bug Yang等为代表的程序员是大多程序员成长的真实写照
    发表于 03-08 14:06

    疯狂的程序员

    疯狂的程序员
    发表于 08-04 13:09

    程序员修养

    程序员修养
    发表于 08-19 22:36

    与一群天才程序员一起工作是什么感觉?

    我是公司里一个特别普通的程序员,在我周围有很多在一小时内就能毫不费力地写出好几百行高效的代码的真正的天才程序员,而我要花更长时间来写,并且写出来的代码还需要进一步调整。我感觉在他们眼里我很没有存在感,在背后议论我做的不够好。该怎
    发表于 12-03 14:58

    程序员的快乐:那些小细节

    近日,有人撰写了一篇文章,谈到了影响程序员快乐的各种因素,特别强调了那些不太为人所注意的小细节。除了薪水、晋升机会等显而易见的因素外,日常的工作我们还需要注意一些小细节,也许程序员的快乐就是源自于
    发表于 12-11 14:10

    优秀程序员是怎样炼成的?

    最基本的要求是能自主地编程。只有在经过多年的学习实践之后,我们才能超越写一些简短程序的基础水平。而仅靠上课或者看书是做不成能力卓群的程序员的,不断的练习和实践才是唯一的正途。学校那些所谓的CS
    发表于 02-14 20:45

    程序员的幽默——献给所有程序员

    1. 某程序员对书法十分感兴趣,退休后决定在这方面有所建树。于是花重金购买了上等的文房四宝。一日,饭后突生雅兴,一番磨墨拟纸,并点上了上好的檀香,颇有王羲之风范,又具颜真卿气势,定神片刻,泼墨挥毫
    发表于 10-31 18:43

    程序员越老越优秀吗?

    Peter Knego 向我们展示了一些有趣的东西: 官方数据:程序员年纪越大越出色、越稀有。他使用StackOverflow的声誉值和其它几个指标来印证他的观点。他的总结是:随着年龄的增加,程序员
    发表于 10-25 10:04

    程序员的春联

    程序员写春联,秒杀全场!网友不愧是聪明绝顶的“程序猿”!
    发表于 04-08 11:39

    Java程序员学习各阶段的建议有哪些?

    面试 顺谈Java程序员学习各阶段的建议
    发表于 05-01 13:07

    #1024程序员节#话题讨论:不会填坑的程序员不是一个好程序员

    作为程序员的你是否经常遇到这样的情景:负责开发的项目遇到线上bug,心想这不是我的锅,先不管了,放着吧;代码写完后,隐隐感觉有问题,可程序跑得通,先用着吧;接手一个老系统,这什么破代码,算了,改吧改
    发表于 10-23 14:51

    作为一个程序员必须知道哪些内存的硬核知识点?

    作为一个程序员必须知道哪些内存的硬核知识点?
    发表于 10-13 08:26

    程序员眼里内存(上)

    本节是操作系统系列教程的第三篇文章,属于操作系统第一章即基础篇,在真正开始操作系统相关章节前在这一部分回顾一些重要的主题,算是温故知新吧,以下是目录,由于本文篇幅较多因此接下来会分三次发布,目录中黑体为本篇内容。
    的头像 发表于 02-24 14:07 249次阅读

    程序员眼里内存(下)

    在各种编程语言中我们应该经常听到两个词,那就是引用或者指针。这两个词都是和内存相关的,指针和引用的作用都是“如何找到存放在内存上的数据”。
    的头像 发表于 02-24 14:12 271次阅读
    <b class='flag-5'>程序员</b><b class='flag-5'>眼里</b>的<b class='flag-5'>内存</b>(下)