首页 > 系统相关 >内存为什么要划分堆区、栈区?除了堆栈之外内存还有什么分区?

内存为什么要划分堆区、栈区?除了堆栈之外内存还有什么分区?

时间:2024-11-01 17:16:54浏览次数:3  
标签:栈区 函数 堆区 内存 数据结构 分配

最近在学习计算机底层相关的知识,看到内存这块内容时有个疑问,为什么要提出堆、栈的概念?当初是为了解决什么问题呢?除了堆栈外内存还存在其他分区吗?大学里学过微机原理涉及到一些相关内容但是到如今已经忘得差不多了。还是重新找资料记录一下学习过程吧!

堆、栈的提出

计算机在最开始的时候,既没有堆也没有栈。当下图中的冯·诺依曼架构提出的时候,只是说计算机要有“存储器”。

所以,早期的计算机整个内存空间都是由用户任意使用,不存在什么分区,其中的每个bit都属于全局变量。这样的话会导致错误的操作,破坏系统的稳定性和安全性,同时内存管理也会变得很复杂性能也会降低。

在二十世纪六十年代,一些计算机科学家提出了ALGOL 58语言,代码示例如下:

procedure Absmax(a) Size:(n, m) Result:(y) Subscripts:(i, k);
    value n, m; array a; integer n, m, i, k; real y;
comment The absolute greatest element of the matrix a, of size n by m,
    is copied to y, and the subscripts of this element to i and k;
begin
    integer p, q;
    y := 0; i := k := 1;
    for p := 1 step 1 until n do
        for q := 1 step 1 until m do
            if abs(a[p, q]) > y then
                begin y := abs(a[p, q]);
                    i := p; k := q
                end
end Absmax

ALGOL语言提出了结构化编程的理念,将代码划分成块,比如if块、循环块、函数块,每块用begin...end包起来。在每块里面存在的局部变量也要本地化,不能再用全局变量,避免变量耦合。

那么,现在就要思考一个问题了 ,如何实现变量的局部化呢?从内存的角度考虑就是在进入每个块的时候为这个块新开辟一块内存,这块内存只属于这个块。有一点需要注意的是块之间是可以嵌套的,A可以调用B,B可以调用C,而且这个嵌套结构有个特点:程序执行时,最后执行的块会最先执行完,所以后申请的块内存会先释放,这属于是后进先出的数据结构。

上面就是栈的特点,遇到变量先放进内存,退出块时再取出来,Last-In-First-Out数据结构。并不是科学家发明了“栈”这个概念,应用到了计算机语言中,而是在实现结构化编程时,发现必须使用一种LIFO的数据结构,这个结构和货栈堆货是一个道理,先放的货在下边,后放的货在上边,取的时候先取上边后放的,再取下边先放的,既然这样,那这个LIFO结构干脆就叫“栈(Stack)”吧。

在二十世纪七十年代,结构化编程思想被大家接受,这就造成了对内存的放取操作。为了提高效率,DEC在推出的PDP-6计算机中,率先提供了PUSH、POP、PUSHJ、POPJ四个CPU指令。

”堆“这个概念是在BCPL语言中最先提出来的,提供了GETBLK(n)和FREEBLK(p)两个函数。这两个函数可以在运行时动态申请一块内存。终于不用在代码里写死数据体大小了!BCPL语言发展到C语言,就是著名的malloc和free函数。

这就是“堆”,为了能让你推迟到运行时再决定一块数据的大小,而不是在写代码时就必须决定。注意这一点和“栈”是不同的,绝大多数语言栈上数据的大小必须在编译期决定。

堆区、栈区之间的区别

一、管理方式不同

  1. 栈区

    • 自动管理:栈区的内存管理通常是自动进行的。当函数被调用时,系统自动为函数的局部变量和参数分配栈空间;当函数返回时,这些空间会自动被释放。这种自动管理方式使得栈的使用非常方便,不需要程序员显式地进行内存分配和释放操作,降低了编程的复杂性和出错的可能性。
    • 快速分配和释放:由于栈的管理是基于简单的后进先出(LIFO)原则,内存的分配和释放非常迅速。这对于频繁调用的函数和需要快速执行的代码非常重要,可以提高程序的执行效率。
  2. 堆区

    • 手动管理:堆区的内存管理由程序员手动控制。程序员可以在运行时根据需要动态地分配和释放内存,使用诸如 mallocnew 和 freedelete 等函数。这种手动管理方式虽然更加灵活,但也增加了编程的复杂性,需要程序员确保正确地分配和释放内存,以避免内存泄漏和悬空指针等问题。
    • 灵活的大小和生命周期:堆区的内存分配更加灵活,可以分配任意大小的内存块,并且内存块的生命周期可以由程序员控制。这对于需要在程序运行过程中动态调整内存使用的情况非常有用,例如处理动态数据结构(如链表、树等)或需要长时间存储数据的情况。

二、内存使用特点不同

  1. 栈区

    • 大小有限:栈的大小通常是有限的,一般在几兆字节到几十兆字节之间。这是因为栈的空间是在程序启动时预先分配的,并且栈的增长是向下的(朝着低地址方向),如果栈空间用尽,会导致栈溢出错误。
    • 局部性好:由于栈是用于存储函数调用的上下文信息,函数的局部变量和参数通常在短时间内被频繁访问,具有较好的局部性。这种局部性有利于提高 CPU 的缓存命中率,从而提高程序的执行效率。
  2. 堆区

    • 大小相对较大:堆的大小通常比栈大得多,可以根据系统的可用内存进行动态调整。这使得堆区可以满足程序对大量内存的需求,特别是在处理大型数据结构或长时间运行的程序中。
    • 分配和释放不连续:堆区的内存分配和释放是不连续的,不同的内存块可能在不同的时间被分配和释放,导致内存空间的碎片化。这可能会影响内存的分配效率,特别是当需要分配较大的连续内存块时。

三、数据存储需求不同

  1. 栈区

    • 存储临时数据:栈区主要用于存储函数调用过程中的临时数据,如局部变量、函数参数和返回地址等。这些数据的生命周期通常与函数的执行时间相关,函数返回后,这些数据就不再需要了。
    • 快速访问:由于栈的管理方式简单,栈区的数据访问速度通常很快。这对于需要频繁访问的局部变量和参数非常重要,可以提高程序的执行效率。
  2. 堆区

    • 存储动态数据结构:堆区主要用于存储动态分配的数据结构,如链表、树、动态数组等。这些数据结构的大小和生命周期在程序运行过程中可能会发生变化,需要动态地分配和释放内存。
    • 长期存储数据:堆区还可以用于存储需要在程序运行过程中长时间保存的数据,例如在文件读取、网络通信等场景中,需要将数据存储在堆区以便在不同的函数之间传递和处理。

标签:栈区,函数,堆区,内存,数据结构,分配
From: https://blog.csdn.net/weixin_47119466/article/details/143362690

相关文章

  • (C语言)动态内存管理,柔性数组
    1.为什么存在动态内存分配动态内存管理是C语言提供给我们自主维护空间大小的能力C语言提供了一个动态内存开辟的函数:void*malloc(size_tsize);这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。·如果开辟成功,则返回一个指向开辟好空间的指针。·......
  • 【JVM详解&JVM优化】JVM内存模型
    一、介绍:        JVM是java虚拟机,JVM(JavaVirtualMachine)。对于Java不需要管理垃圾,jvm会自动帮助我们回收垃圾,但更好的掌握jvm如何帮助回收垃圾的,能让我们的系统更加稳定。        所有的Java程序都需要在JVM中运行,JVM也是Java跨平台的原理所在,对于不同......
  • Python内存模型
    Python深浅拷贝一.变量的内存模型x=1print(id(x))#94454455464992print(id(1))#94454455464992print(id(5))#94454455465120x=5print(id(x))#94454455465120print(id(1))#94454455464992print(id(5))#94454455465120"""Python更改变量值,发生变化......
  • Java面试题中高级进阶(JVM篇Java内存)
    前言本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!说说Java内存结构?说说对象分配规则?描述一下JVM加载class文件的原理机制?似乎有点模糊了,那就大概看一下面试题吧。好记性不如烂键盘***12万字的java面试题整理***Java内存结构方法区和堆是所有线程共享的内存区域;而j......
  • 内存管理相关——malloc,mmap,mlock与unevictable列表
    一、背景之前的内核内存子系统的章节里已经介绍了内存回收有关的MIGRATE_TYPE的概念并做了不少的相关实验。详细见我之前写的博客 内存回收相关内核基础概念——MIGRATE_TYPE_kreclaimable没有回收-CSDN博客。锁内存相关的常用函数有四个,SetPageReserved/mlock/get_user_pa......
  • 【Linux】进程间通信(命名管道、共享内存、消息队列、信号量)
    ......
  • 深入计算机语言之C++:内存管理
    ......
  • c语言:动态内存管理中的malloc和free,calloc和realloc
    为什么要有动态内存分配?通过之前的学习,我们已经掌握的内存开辟方式有:inta=20;//在栈空间上开辟四个字节chararr[10]={0};//在栈空间上开辟10个字节的连续空间上述空间的开辟的大小是固定的数组在申明的时候,必须指定数组的长度,数组空间一旦确定了大小不能进行调整。......
  • 19 内存与储存介质
    一般电脑内存是非永久性,电源断了,内存数据将全部丢失存储器是永久性的,除非被删除或覆盖最初用打孔纸卡纸带来存储,后来用延迟线存储器,利用声波来存储1,0数据。但只能顺序读取,不能任意读取出现磁芯存储器,电流方向改变磁性也改变,将磁芯排列成网格。这种可以随意读取。甚至刚......
  • Linux内存操作命令
    du(diskusage)命令用于查看文件和目录占用的磁盘空间。以下是du命令的一些常用选项和用法详解:基本用法查看当前目录下所有文件和子目录的大小:du默认情况下,du会以块(通常是1K)为单位显示每个文件和目录的大小。查看特定目录的大小:du/path/to/directory常用选项-h:以人类......