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

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

3天内不再提示

程序员眼里的内存(上)

jf_78858299 来源:码农的荒岛求生 作者:码农的荒岛求生 2023-02-24 14:07 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

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


什么是内存

C/C++内存模型

堆区与栈区的本质

JavaPython等内存模型

Java内存模型

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

Python内存模型

指针与引用

进程的内存模型

幻想大师-操作系统

总结


什么是内存

0和1这两个简单的数字能做什么?在其它学科中也许什么都做不了,但是在计算机科学中这就是全部。精彩纷呈的计算机世界正是构筑在这样两个简单数字之上。

内存本身其实非常简单,内存的作用就是用来装数字0和数字1的,如图所示,图中的一个盒子就是内存的一个基本单元,装的不是0就是装的1。

内存由一大堆的“盒子”组成,每个盒子中要么是0要么是1,其中8个盒子被称之为一个“字节”,每8个盒子也就是一个字节都有一个编号,这些编号就是简单的从0开始依次累加的,这个编号就被称之为“ 内存地址 ”。其中左边的数字是内存地址,每一排是一个字节,图中展示的就是一个8字节大小的内存。

而对于我们平时使用的比如2G、4G甚至8G大小的内存来说,只不过就是“盒子”多一点能装的01多一点而已,本质上和我们在这里展示的8字节大小的内存没有任何区别。

在后面的章节中我将用右图来表示内存,但是你的大脑里一定要有左图这样一个概念。当计算机在执行我们的程序时,无论是我们的机器指令还是机器指令操作的数据,都需要存放在这些小盒子中(内存)。

以上就是从硬件角度来看内存,那么从编程语言上来看,程序员应该如何理解内存呢?

C/C++内存模型

对于C/C++程序员来说,常用的int,char等变量都被装在盒子中,char值只需要一排盒子就能装下(8bit),一个int值一般需要四排盒子才能装得下。连续几排装有同样类型变量的盒子就是数组(array),连续几排装有不同类型变量的盒子就是结构体(struct),C/C++语言中不管多么复杂的数据结构都是在此基础上构建出来的,都需要装在这些盒子里,没什么大不了的。

现在你已经知道了对于C/C++程序员来说,我们使用的变量是直接放在内存中的(盒子), 每一排盒子的地址就是我们熟知的“指针” ,请记住,指针就是你使用的变量在内存中的地址,仅此而已。

C/C++程序在被执行时,需要在内存中划出两段区域用于存放数据,这两个区域就是我们熟悉的堆(Heap)和栈(Stack),也称堆区和栈区,如图所示,其中数据段和代码段我们已经熟悉了,在这里我们将进一步完善C/C++程序在内存中的样子,如图所示,其中堆区紧邻数据段,在数据段之上,而栈在最上方,栈和堆之间是尚未被使用的内存,随着程序的运行,当程序申请内存时栈区和堆区之间的空隙会减小,当程序释放内存后空隙会扩大,这就是C/C++程序的内存模型。

每个函数运行时都会在栈区上占用一块内存,这块内存中保存的是调用函数的参数以及函数中的定义的局部变量,这些变量在函数调用完成后会被释放。从这里可以看出栈上的变量无需程序员关心其释放问题,当函数调用完毕后会自动释放所占用的空间。

和栈上的变量不同的是,堆上分配的内存不会像栈一样被自动释放,在堆上分配的内存需要程序员手动释放,如果程序员在堆上分配了一块内存,但在使用完后忘记释放,这种情况就被称之为“内存泄漏”,所谓“内存泄漏”就是使用完毕后的内存没有释放掉,但是这块内存也不能被用作其它地方从而导致堆占用的内存不断增大,表现出来的就是如果我们去检测程序所占用的内存,会发现程序所占用的内存不断增大,当操作系统是不可能坐视某个进程不断吞噬掉系统内存的,当出现系统内存资源不足时将触发操作系统的保护机制,这在Linux中就是著名的OOM Killer,即Out Of Memory Killer,OOM Killer会根据一些策略Killer有问题的进程,这个进程通常都是占用内存最多的那个。

下面我们用一小段C代码来实际演示一变量是如何在堆区栈区上分配的,不用担心,这段代码非常简单:

include

如图所示,这就是以上代码运行过程中的样子,你会发现,每个函数在被执行的时候都在栈区上占有一小段,在这一小段中存放当前函数中定义的局部变量和传入函数的参数。每个函数所占用的这一段内存有一个很形象的名字,叫做“栈帧(stack frame)”,原因就在于栈是随着函数调用一帧一帧增加的,每个函数在被调用时都会在栈上分配一帧,所以就叫栈帧。这个词请大家不必去深究,每个被调函数在栈区上做占用的内存总要有个名字,栈帧只不过比较形象而已。

这段代码中,main函数会调用函数f1,f1会调用函数f2(),其中变量a,b,c以及heap依次被放在各自函数的栈帧中,值得注意的一点在于, heap这个变量本身是在栈上的,但是heap所指向的内存是分配在堆上的 ,heap本身仅仅保存的是4这个值在内存中的 位置 ,比如这里的0x10,表示的就是4这个值放在了内存0x10的这个位置上,heap就是C/C++语言中所谓的指针。

你会发现随着函数的调用,栈是不断在扩大的,当f2,f1执行完毕返回main时就是如下图所示的样子。

从图中我们可以看出,f2在执行完毕后,f2所占用的内存就被回收了,所谓“回收”就是这块内存又可以用作其它用途了。f1执行完毕后所占用的内存同样也被回收,这样我们就又回到了main()函数中。

这个过程中我们还会发现一个很有意思的现象就是最先被使用的栈帧其实是最后才被释放的,这种先进后出的性质就被称之为“栈”,如下图所示。所以你会看到“栈“这个词更多的是指顺序上的先进后出,只不过函数调用时所占用的内存在使用方式上也是先进后出的,所以这块内存就被称之为栈区了。

在讲解完栈之后,我们来看看堆,不同于像a,b,c这样存在于栈区上的变量,栈区上的变量可以在函数执行完成后被自动释放掉,在堆区上的分配内存除非程序员手动调用free,delete明确的告知内存使用完毕,否则这块内存就会一直被占用而不能用作其它用途,这就是堆区。

你可能会问,什么样的变量在需要在堆上分配呢,我们知道,函数调用完成后栈上的分配的局部变量会因为栈帧被释放而不再可用,堆区的存在就是为了解决这个问题,堆区中申请的内存不会因为栈帧的释放而不再可用,使得变量的生命周期不再局限于某个函数,其生命周期是靠程序员用malloc(new)以及free(delete)来控制的,这样的变量在使用时可以跨越函数调用。

另外一点值得注意的是,f2函数中我们在堆上申请了一块内存用来存放整数,但是f2执行完成后并没有去释放这块内存,根据堆的性质我们知道这块函数在接下来的运行过程中无法再被使用,就好像这块内存被遗忘了一样,这就是内存泄漏。

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

    关注

    9

    文章

    3173

    浏览量

    76112
  • 操作系统
    +关注

    关注

    37

    文章

    7328

    浏览量

    128621
  • C++
    C++
    +关注

    关注

    22

    文章

    2122

    浏览量

    76705
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    数据显示:中国程序员是世界最牛的程序员

    根据我们的数据显示,中国和俄罗斯拥有最具才华的程序员。中国程序员在数学、功能程序设计和数据结构方面超过了世界其他国家的程序员,而俄罗斯程序员
    发表于 12-14 20:33 798次阅读

    用户和程序员之间的关系

    我曾经说过,程序员不是一般的人,是具有某种超能里的人。但问题是,程序员往往意识不到自己的这种特异功能,在他们的眼里,会认为自己很普通,跟常人一样,所以,程序员能做到的事情,其他人——比
    的头像 发表于 11-16 16:10 2535次阅读

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

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

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

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

    程序员如何定义

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

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

    ?你又是哪一类的程序员?“菜鸟”程序员和“大神”程序员差在哪里?真是差在技术上了吗?那不是差在技术那差在了哪里?
    的头像 发表于 06-03 15:56 3053次阅读

    什么是程序员

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

    程序员的未来

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

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

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

    如何定义程序员

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

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

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

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

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

    程序员的类型

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

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

    。不幸的是,两者都没有使用计算机的内存子系统或CPU的缓存的结构和成本大多数程序员都很理解。本文解释了现代商品硬件使用的内存子系统的结构
    发表于 11-23 16:55 0次下载

    程序员眼里内存(下)

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