堆栈的简单认识

    写堆栈,一是因为在工作中有时会碰到,脑子里有这个概念但是又没有一个完整的框架;二是我刚开始工作时,导师问我malloc,我竟完全不知这个函数,更不知道malloc是从堆中分配内存,所以现在补上。

文中很多语句都是引用他人,无意抄袭,在此说明一下,若有冒犯,请告知。

这篇文章先从程序内存布局讲起,说明堆栈在Linux进程内存空间中的位置,然后再分别说明堆栈的基本概念、作用。

Linux进程内存布局

现代的应用程序都是运行在内存空间中的,在32位的系统里,这个内存空间拥有4GB的寻址能力。实际上,每个应用程序(或者说进程)都有自己独立的内存空间,即通过虚拟内存来实现(具体虚拟内存知识暂不介绍)。

大多数操作系统都会将4GB的内存空间中的一部分分配给内核使用,应用程序无法访问这一段内存,这一部分内存空间称之为内核空间。Linux默认将高地址的1GB内存空间分配给内核。剩下的3GB内存空间称之为用户空间。在用户空间里,也有许多默认的内存区域,例如堆栈,可执行文件映像,保留区。下图是一个Linux典型的内存布局:

一、什么是栈

栈是现代计算机程序里最重要的概念之一,几乎每一个程序都使用了栈,没有栈就没有函数,没有局部变量。

在经典的计算机科学中,栈被定义为特殊的容器,用户可以将数据压入栈中(入栈,push),也可以将已经压入栈中的数据弹出(出栈,pop),且栈遵守一条规则,即先入后出。

经典的操作系统中,栈总是向下生长。在i386下,栈顶由称为esp的寄存器进行定位,压栈的操作会使栈顶的地址减小,弹出的操作使栈顶的地址增大。

二、栈的作用是什么

栈在程序运行中具有举足轻重的地位,最重要的,栈保存了一个函数调用所需要的维护信息,通常被称为堆栈帧(stack frame)或活动记录。堆栈帧一般包括以下几方面的内容:

--函数的返回地址和参数

--临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量

--保存的上下文:包括在函数调用前后需要保持不变的寄存器

一、堆的定义和作用

光有栈对于面向过程的程序设计还远远不够,因为栈上的数据在函数返回的时候就会被释放掉,所以无法将数据传递至函数外部。而全局变量无法动态产生,只能在编译的时候定义,很多情况下缺乏表现力。在这种情况下,堆(heap)是唯一的选择。

堆是一块巨大的内存空间,常常占据整个虚拟空间的绝大部分。在这片空间里,程序可以请求一块连续内存,并自由的使用,这块内存在程序主动放弃之前会一直保持有效。

malloc是libc里面实现的一个函数,中文叫动态内存分配,用于从堆中获取内存。但是malloc是如何实现的呢?有一种实现方法是,将进程的内存管理交给操作系统去处理,既然内核管理着进程的地址空间,那么如果它提供一个系统调用,可以让程序使用这个系统调用来申请内存,这是一种理论上可行的方法,但是实际这样去做性能会非常差,因为每次程序申请或者释放堆空间都需要进行系统调用,而系统调用的性能开销非常大,当程序对堆的操作越频繁时,这样做的后果是会严重影响程序的性能。比较好的做法是程序向操作系统申请一块适当大小的空间,然后由程序自己管理,而具体来讲,管理着堆空间分配的往往是程序的运行库。

运行库相当于是向操作系统“批发”了一块较大的堆空间,然后“零售”给程序用。当全部“售完”或者有大量的内存需求时,再根据实际需求向操作系统“进货”。运行库在向程序零售堆空间时,必须管理他批发来的堆空间,不能把同一块地址出售两次,于是运行库需要一个算法来管理堆空间,即堆的分配算法。

时间: 2024-08-29 09:57:51

堆栈的简单认识的相关文章

每天进步一点点——Linux系统中的异常堆栈跟踪简单实现

转载请说明出处:http://blog.csdn.net/cywosp/article/details/25002201 在Linux中做C/C++开发经常会遇到一些不可预知的问题导致程序崩溃,同时崩溃后也没留下任何代码运行痕迹,因此,堆栈跟踪技术就显得非要重要了.本文将简单介绍Linux中C/C++程序运行时堆栈获取,首先来看backtrace系列函数--使用范围适合于没有安装GDB或者想要快速理清楚函数调用顺序的情况 ,头文件execinfo.h int backtrace (void **

关于JAVA堆栈的简单说明

关于堆栈的说明: 1.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2. 堆栈的优劣势 栈: 优势:存取速度比堆要快,仅次于直接位于CPU中的寄存器.栈数据可以共享 缺点:存在栈中的数据大小与生存期必须是确定的,缺乏灵活性. 堆: 优势:可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据. 缺点:由于要在运行时动态分配内存,存取速度较慢. 3. Jav

堆栈入门-简单计算器模板-中缀转后缀

题目链接 后缀表达式又称逆波兰表示法,不含括号,运算符放在两个参与运算的语法成分的后面. 后缀表达式运算求值 自左向右顺序扫描后缀表达式.最后栈中的数字就是答案. (1)如果是数字,则压入栈中. (2)如果是运算符,就从栈中弹出两个数字进行运算,将运算结果压入栈中. 中缀表达式转后缀表达式 从左向右扫描中缀表达式. (1)当输入为数字时,直接输出到后续表达式序列中. (2)当遇到开括号时,将其入栈. (3)当遇到闭括号时,先判断栈是否为空,若为空,则表示括号不匹配,报告异常并退出.若非空,则将栈

内置对象Math,Array,String,Date,堆栈,简单数据复杂数据类型

JavaScript 内置对象 Math Math.PI; // 返回圆周率 Math.max(1, 2); // 返回最大值,非数字返回NaN, 空返回 -infinity Math.min(1, 2); // 返回最小值,非数字返回NaN, 空返回 infinity Math.abs(1); // 绝对值 字符串型数字会隐式转换,非数字返回 NaN Math.floor(1.9); // 向下取整; Math.ceil(1.1); // 向上取整: Math.round(1.5); // 四

堆栈入门-简单计算器

题目链接:https://www.nowcoder.com/questionTerminal/5759c29a28cb4361bc3605979d5a6130 AC代码: #include <stack>#include <stdio.h> #include <ctype.h> using namespace std; char str[220]; int mat[][5]={ 1,0,0,0,0, 1,0,0,0,0, 1,0,0,0,0, 1,1,1,0,0, 1,

Android下打印调试堆栈方法(转)

转自:http://blog.csdn.net/freshui/article/details/9456889 打印堆栈是调试的常用方法,一般在系统异常时,我们可以将异常情况下的堆栈打印出来,这样十分方便错误查找.实际上还有另外一个非常有用的功能:分析代码的行为.Android代码太过庞大复杂了,完全的静态分析经常是无从下手,因此通过打印堆栈的动态分析也十分必要. Android打印堆栈的方法,简单归类一下 1. zygote的堆栈dump 实际上这个可以同时dump Java线程及native

JavaScript实现数据结构中的队列和堆栈

今天在项目中要使用JavaScript实现数据结构中的队列和堆栈,这里做一下总结. 一.队列和堆栈的简单介绍 1.1.队列的基本概念 队列:是一种支持先进先出(FIFO)的集合,即先被插入的数据,先被取出! 如下图所示: 1.2.堆栈的基本概念 堆栈:是一种支持后进先出(LIFO)的集合,即后被插入的数据,先被取出! 如下图所示: 二. 在JavaScript中实现队列和堆栈 在JavaScript中实现队列和数组主要是通过数组,js数组中提供了以下几个方法可以让我们很方便实现队列和堆栈: sh

转: iOS崩溃堆栈符号表使用与用途

转:http://bugly.qq.com/blog/?p=119 iOS崩溃堆栈符号化,定位问题分分钟搞定! 2015.3.16 腾讯Bugly 微信分享 最近一段时间,在跟开发者沟通过程中,萝莉发觉大家对iOS的应用符号表还不是很清楚,除了咨询关于符号表生成.配置的问题以外,对Bugly崩溃分析需要配置符号表也存在疑问. 在这里,萝莉就给大家分享下关于iOS符号表的一些内容. 首先,进行常识“脑补”. 1. 符号表是什么? 符号表就是指在Xcode项目编译后,在编译生成的二进制文件.app的

Android下打印调试堆栈方法

打印堆栈是调试的常用方法,一般在系统异常时,我们可以将异常情况下的堆栈打印出来,这样十分方便错误查找.实际上还有另外一个非常有用的功能:分析代码的行为.android代码太过庞大复杂了,完全的静态分析经常是无从下手,因此通过打印堆栈的动态分析也十分必要. Android打印堆栈的方法,简单归类一下 1. zygote的堆栈dump 实际上这个可以同时dump java线程及native线程的堆栈,对于java线程,java堆栈和native堆栈都可以得到. 使用方法很简单,直接在adb shel