学习笔记:内存,堆栈,到底为何物?

     在网上看到了一篇关于面试的博客文,突然发现自己对于这个博主而言简直差的是十万八千里,他提到的许多技术我尽然一个也答不上来。于是就开始反思,还是要抱一抱佛脚。左看右看发现了内存这个面试的万恶之源。

     说实话对于内存这种东西即使是一点也不了解的人也能写出许多的程序,但有一个现实问题就是面试时总是会用这些基础知识来考面试的人。我曾经出面试题的时候也做过一样的事情,但是想想自己其实也不懂。最近开始更新自己的简历,期望来年能找到一份新的工作,才想起自己还是那个什么都不懂的开发人员,还是要面对面试官的考问。

话说什么是内存?

内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。内存(Memory)也被称为内存储器,其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来,内存的运行也决定了计算机的稳定运行。 内存是由内存芯片、电路板、金手指等部分组成的。 ——摘自百度百科

看完后简单无法直视,这和我想了解的东西有什么关系呢?

我的理解为:内存是一种存储器,硬件上来说就是一种可以快速存储计算机数据,CPU将这些数据取得运算。内存就像一个大数组,可以存放许多数据。

     这里就有一个很重要的问题,CPU和内存储器都是硬件,谁来负责操作这些硬件呢?这就要说到操作系统了。我们通常用的windows、linux、unix这些操作系统,那么就很自然的想到了对于内存操作与管理其实还是由操作系统提供了机制,应用程序在这个基础上再完成相应的内存操作。

网上找了找资料,windows和linux的内存管理机制来看,都将内存划分为了物理内存和虚拟内存。

  • 物理内存

    物理内存就是系统硬件提供的内存大小,是真正的内存,说土点就是那内存条

  • 虚拟内存

    虚拟内存就是为了满足物理内存的不足而提出的策略,它是利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为交换空间(Swap Space)。然后对于内存的操作需要有一种访问的方法,既然内存是CPU的暂时存数据的地方,那么CPU读取数据时肯定要有方法去读取吧,这就是要说到-内存地址。

考虑到内存资源总是有限的,而对于多任务的操作系统来说,应用程序越多自然占用的就越多,那如何合理的分配内存资源呢?有两种划分方法:分段、分页。

参考文章:http://blog.csdn.net/qingfeng_happy5/article/details/4322723

到这我倒是有了一些简单的理解:

所有的应用程序都是通过编绎器编绎为了可执行文件,在这个文件里会有许多的描述内容和程序指令。当这个应用启动时,操作系统会创建一个进程,并在这个进程中分配一个地址空间,而后随着应用的不断执行和操作系统与CPU的调度会不断的在虚拟地址和物理地址之间做映射,从而拥有了真实的内存空间,可以输入指令和数据供CPU执行。

再来看看堆栈

堆栈这个名词不陌生,但对于许多开发人和我一样只知其名,不知其实。写这个笔记原因是因为我没有理解内存与堆栈为什么总会放在一起讨论?于是边看资料边记录笔记。

在计算机领域,堆栈是一个不容忽视的概念,堆栈是两种数据结构。堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除。在单片机应用中,堆栈是个特殊的存储区,主要功能是暂时存放数据和地址,通常用来保护断点和现场。要点:堆,列队优先,先进先出[1] 。栈,先进后出(First-In/Last-Out)。——摘自百度百科

看到这个概念我最大的疑问是,堆栈是两种数据结构?这就是典型的数据结构没学好的人的反应,呵呵。没办法只能继续寻找资料学习。于是在学习过程中慢慢的就有些理解。

先看看堆栈的一些定义和说明

栈(数据结构):一种先进后出的数据结构。——摘自百度百科

    这句话让我想到一个问题,那就是先进后出的这种数据结构有什么作用呢?带着这个疑问就去寻找栈的应用场景,下面这个场景突然让我些明白了什么:

    “栈可以用来在函数调用的时候存储断点,做递归时要用到栈!”

    对呀,当我们的代码在运行的时候不就可以看到一个“栈”嘛,先把方法压栈,然后逐个的取出来执行。这样代码的效率就高了许多,而且顺序不会出错。

    好了,有了这个理解再看下面的内容:

栈(操作系统):由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。   栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,但缺点是,由于要在运行时动态分配内存,存取速度较慢。——摘自百度百科

一般存在栈中的数据都有哪些?比如值类型(特别是基本数据类型)和对象句柄之类。

看了栈对于堆的理解就要好多了,先看看定义:

堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。 堆(数据结构):堆可以被看成是一棵树,如:堆排序。      ——摘自百度百科

堆(英语:heap),是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。在队列中,调度程序反复提取队列中第一个作业并运行,因为实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权。堆即为解决此类问题设计的一种数据结构。     ——摘自维基百科

所以堆要灵活的多,分配与释放都可以按需进行。在栈中也说过堆的优点是灵活,缺点也是因为灵活存取效率会低一些。

其实就数据结构来说,堆就是一个数组或者链表,可以看作是一颗完全二叉树的存储结构,他的特点就是先进先出。

总结

有了对内存和堆栈的一些基本概念后,再回头看一下自己的问题,内存和堆栈到底为何物?

我的理解内存是计算机的一个硬件组成部分,是CPU执行指令的数据存储区,内存就是提供了这一块存储空间。想要使用这块存储空间就得用到操作系统,由于与硬件打交道的就是操作系统,而操作系统决定了对内存的管理机制。而应用软件需要对内存进行存取就要用到堆栈,这是两种数据结构,决定了数据在内存空间里的存储结构。

应用程序在内存中的存储结构是由编绎器决定的。这个我的描述可能不准确,下面说一下C++中内存的分区机制可能会比较好理解一些。 

  • ,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。 
  • ,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。 
  • 自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。 
  • 全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。 
  • 常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)

写到这感觉还是有许多的疑问,为什么内存的管理会使用这些数据结构呢?堆栈之外有没有更好的办法来管理?这是否与计算机的发展历史有关呢?

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

Android热修复技术总结

插件化和热修复技术是Android开发中比较高级的知识点,是中级开发人员通向高级开发中必须掌握的技能,插件化的知识可以查我我之前的介绍:Android插件化。本...

29960
来自专栏祝威廉

Spark Tungsten in-heap / off-heap 内存管理机制前言

分析方式基本是自下而上,也就是我们分析的线路会从最基础内存申请到上层的使用。我们假设你对sun.misc.Unsafe 的API有一些最基本的了解。

12330
来自专栏向治洪

Android热修复技术总结

插件化和热修复技术是Android开发中比较高级的知识点,是中级开发人员通向高级开发中必须掌握的技能,插件化的知识可以查我我之前的介绍:Android插件化。本...

37970
来自专栏平凡文摘

11 个简单的 Java 性能调优技巧

15620
来自专栏QQ空间开发团队的专栏

一个 ClassLoader 引起的 JNI 链接错误

Android 插件化工程具有减少方法数和包大小,易于扩展等优势,深得大型工程的青睐,但同时插件化也会引起一些意想不到的麻烦。我们最近在做的插件工程就遇到了一个...

65800
来自专栏精讲JAVA

11 个简单的 Java 性能调优技巧

大多数开发人员理所当然地以为性能优化很复杂,需要大量的经验和知识。好吧,不能说这是完全错误的。优化应用程序以获得最佳性能不是一件容易的事情。但是...

21380
来自专栏技术记录

谈谈序列化—实体bean一定要实现Serializable接口?

导读:最近在做项目的过程中,发现一个问题,就是我们最开始的时候,传递参数包括返回类型,都有map类型。但是由于map每次都要匹配key值,很麻烦。所以在之后就将...

46580
来自专栏nummy

在Flask中使用ajax的POST方法传递数组

如果在服务器端使用flask中的request.form.get方法是无法获取到数据的,因为我们传递的是数组,而不是单个元素。 怎么办? flask还提供了...

12410
来自专栏ionic3+

safari日期转换的注意事项

考虑到苹果设备使用,所以不能忽略safari,明明早就知道要留意了,结果新的项目又忽略了,小记一下:

8830
来自专栏向治洪

一个ClassLoader引起的JNI链接错误

前言 Android插件化工程具有减少方法数和包大小,易于扩展等优势,深得大型工程的青睐,但同时插件化也会引起一些意想不到的麻烦。我们最近在做的插件工程就遇到了...

257110

扫码关注云+社区

领取腾讯云代金券