操作系统堆栈的那些事

堆栈-操作系统(一) 很早就想写一篇文章,关于操作系统中的堆栈。 说是堆栈,其实就是操作系统如何处理代码的,即如何为代码中的各种类型的变量、常量、方法体(函数体)等等分配内存空间。 了解这些内容,可以帮助我们做一些判断: 帮助我们在程序出错时更快找到错误地点。 帮助们尽可能利用效率高的方式编程。 接下来开始浅析操作系统中的堆栈。 堆:由程序员申请的一片数据区域,并在程序执行完之前由程序员手动释放。类似于链表结... 阅读详情

堆栈是编程中很重要的概念,相信很多人也跳过坑,然后解决之后,继续跳坑。想整理堆栈的概念很久了。最近看了程序员自我修养,就一起整理一下吧。

本文将从几个方面学习一下堆栈
1. 堆栈概念
2. 进程,线程概念
3. 堆栈分配

1. 堆栈概念

  在32位系统,内存的寻址可以达到4G。 理论上,用户可以使用一个32位的指针访问任意内存地址。

int a = 3;
int * p = &a;

std::cout << *p << endl;

  

  然而,事实上并非如此,在编程中我们却常常会遇到segment fault错误,指示我们非法内存访问。证明,有些位置我们是无权访问的,或者说暂时无权访问,只有申请了该内存才能访问。

  其实,大多数操作系统会把4G的内存空间进行划分,比如linux通常会默认把高地址的1G空间分配给内核(内核空间给内核线程执行特权操作,比如维护打开文件表等),剩余的作为内存空间。内存空间又大致分为堆空间,栈空间,代码区等。

*栈: 用户维护函数调用上下文。由高地址向低地址生长,通常以M为单位,由操作系统维护。

  [不能申请占用过大的内存的局部变量,会导致栈爆掉而core.如果变量太大,可以考虑放到全局变量区或者使用堆]

*堆: 动态申请内存,即使用new or malloc等分配到的内存,可以比栈大很多,需用户自己释放

  [new/delete,malloc/free成对出现,否则会导致内存泄露,可以使用查找内存泄露的工具监控或者自己写代码监控]

*代码区:存放代码的内存映像

*保留区:禁止访问的一些区域,比如NULL

  [使用*访问置为NULL的指针会出错,也需要小心野指针]

      内核态和用户态的区别?什么叫做系统调用时会陷入内核

      内核线程和用户线程是存在一定的对应关系,这个由线程库来实现。内核并不感知用户级别的线程。用户需要做一些操作,比如访问文件,开辟共享内存等特权操作但是用户又没有权限时,只能通过系统调用,让操作系统的内核线程来做。称为陷入内核,此时,内核会通过调用相应的中断处理程序来执行特权操作。但是用户往往只能拿到资源的代号而无法拿到资源的实际指针,比如文件描述符。其实是内核系统给进程维护的打开文件表数组下标,而实际的文件指针是存储在下标中的元素。所以,用户拿到了描述符还是只能通过系统调用来进行操作,而无法直接拿到指针进行访问,这样,就绕过了操作系统。这是不被允许的。

2. 进程,线程概念

   实际上,linux将所有运行的实体(进程,线程)称为任务(task),每一个task概念上类似于一个单线程的进程,具有内存空间,执行实体,文件资源等。不过。linux下不同的任务之间可以选择共享内存空间,因而实际上可以定义,共享了一个内存空间的不同任务构成了一个进程,而这些任务则称为进程里的线程。

 接口:fork(写时复制),exec(替换程序),clone

   从数据角度来看,线程数据和进程数据可以分为:

线程私有 现场共享(进程所有)

局部变量(栈,寄存器)

函数参数

TLS数据

全局变量

动态申请的数据(堆)

函数里的静态变量

代码区

打开文件列表

 

 

 

 

 

 

 

3. 堆栈分配

  3.1. 堆

    用于动态分配内存,c语言中使用malloc/free进行申请和释放

int main(){
    char *p = (char *)malloc(1000);
   
    //do_something(p);
      
    free(p);return 0;
}

  那么malloc是怎么实现的呢?对于申请内存这种特权操作,肯定是操作系统内核来做比较合适,但是频繁的进行系统调用,在用户态和内核态之间切换,也就是频繁的调用中断处理程序,性能是较差的。所以,事实上都是通过c语言的运行库封装好的库函数,预申请一块设当的内存,然后零售给程序用,可以采用空闲链表或者位图等来管理。这取决于运行库的实现了。

      比如glibc运行库的malloc函数是这样处理的:对于小于128KB的请求,他会在现有的堆里面,按照分配算法给他分配一块空间并返回,对于大于128KB的请求,则使用mmap()为它分配一块匿名空间(mmap可以映射到某个文件,而把使用mmap申请却不映射到文件的空间称为匿名空间),然后在这块空间里面分配给用户内存。

      3.2. 栈

     栈在程序运行中的作用不言而喻,非常重要。它保存了一个 函数调用所需要维护的信息,称为活动记录,包括

     1. 函数的返回地址,参数

     2. 临时变量

     3. 上下文:寄存器

      在i386中,一个活动记录用ebp和esp两个寄存器来划定范围,esp始终指向栈顶部,任何指令的执行都会改变esp的值,push stack的时候esp减小,pop stack的时候esp增大。而ebp则指向了一个固定位置,表示函数调用的开始。

  •                                                     bubuko.com,布布扣

      当调用函数时,

      a. 把参数按照从右至左的顺序压栈

      b. 当前指令的下一条指令入栈(return address)

      c. 开始执行函数体(先保存old ebp)

      当返回函数时:把old ebp读回寄存器,然后从return address开始执行

 

      那么,函数的返回值是如何传递的呢?

       答案:通过eax寄存器。函数将返回值存储在eax中,然后调用方读取eax。但是,eax本身只有4个字节,大于4个字节的返回值,则是通过eax存储了一个指针,而实际内容在栈上的其他地方。

 

        当返回值是大于4个字节的的数据结构时,在压栈入参数的时候,大概会做一个这样的事情。

        假设函数调用如下

    some_struct foo(int arg1, int arg2);
    some_struct s = foo(1, 2);

    编译器会把把它处理成类似这样的概念

  some_struct* foo(some_struct* ret_val, int arg1, int arg2);
  some_struct s; // constructor isn‘t called
  foo(&s, 1, 2); // constructor will be called in foo

    也就是给它安排一个隐藏的参数,大概流程如下

        a. 首先在栈上额外开辟一片空间,并把这块空间的一部分作为传递返回值的临时对象

        b. 把这个对象的地址作为隐藏参数传递给函数

        c. 函数把数据拷贝给临时对象,并把地址用eax传出

        d. 调用方再把临时对象拷贝给返回值。


转自: http://www.mamicode.com/info-detail-219735.html   码迷网

uc/os-ii操作系统堆栈浅谈 1 声明堆栈大小 在uc/os-ii操作系统的任务切换和中断处理过程中,需要保存处理器的内部寄存器和变量的值,这就 要求每个任务都有自己的堆栈空间。堆栈必须声明为OS_STK类型,并且由连续的内存空间组成,可以静态 分配空间(在编译时分配),也可以动态分配堆栈空间(在运行时分配)。由于采用动态分配方式,会导致 内存中含有大量内存碎片,因此不推荐使用动态分配方式。其两种声明方式如下: 静态 阅读详情

相关推荐

【操作系统】堆栈寄存器sp详解以及栈帧

在x86架构中,函数调用的栈帧(Stack Frame)是函数调用过程中用于保存函数局部变量、返回地址、参数等的一块内存空间。堆栈寄存器是现代处理器的重要组成部分,在嵌入式开发之中,要对此区域的使用十分敏感,因为堆栈寄存器是处理器的重要组成部分,其高效管理对程序运行的稳定性和安全性起着关键作用。, SP)是处理器中一个专门用于管理栈(Stack)的寄存器,它保存了当前栈的顶部地址。接下来,为了进一步的理解堆栈中发生的事,我们使用x86汇编语言说明函数调用栈帧的创建和销毁的过程详情。

猫猫的小茶馆 4896

操作系统中的堆栈

操作系统的堆和栈是指对内存进行操作和管理的一些方式这和数据结构中的堆和栈是有区别的。1. 一般由程序员分配释放,并指明大小,堆被程序申请使用的内存在被主动释 放前一直有效。堆需要由由程序员手动释放,不及时回收容易产生内存泄露。 程序结束时可能由操作系统回收。 2. 栈是存放在一级缓存中的,而堆则是存放在二级缓存中的,堆的生命周期由 虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收),所 以调用这些对象的速度要相对来得低一些,故堆的速度慢于栈的速度 3. 与数据结构中的堆是不同的,分配方式类似于链

Durian_piza的博客 1068

深入理解任务堆栈以及堆栈溢出

前言: 在多任务操作系统中创建任务时,都需要指定该任务的堆栈大小,那么这个堆栈的作用时什么呢?什么情况下需要用到堆栈,以及大小不够时会产生什么异常呢? 1 任务状态 简单分为运行态,就绪态,阻塞态。 运行态:万事俱备,不欠东风(获得CPU控制权); 就绪态:万事俱备,只欠东风(缺少CPU控制权); 阻塞态:万事不俱备(等事件或信号),还欠东风(缺少CPU控制权); 每个任务基本上都会游离于这三种状...

Boooooots的博客 5814

堆和栈区别

①管理方式:栈由编译器自动管理;堆由程序员控制,使用方便,但易产生内存泄露。 ②生长方向:栈向低地址扩展(即”向下生长”),是连续的内存区域;堆向高地址扩展(即”向上生长”),是不连续的内存区域。这是由于系统用链表来存储空闲内存地址,自然不连续,而链表从低地址向高地址遍历。 ③空间大小:栈顶地址和栈的最大容量由系统预先规定(通常默认2M或10M);堆的大小则受限于计算机系统中有效的虚拟

qq_37924084的博客 361

【CPU】堆栈和堆栈指针(个人草稿)

什么是堆栈?堆栈(Stack)是一种后进先出(LIFO, Last In First Out)的数据结构,广泛用于计算机系统中,尤其是在程序执行过程中管理函数调用、局部变量、返回地址等。堆栈通常位于内存的特定区域,称为堆栈段或栈区。特性后进先出(LIFO):最后入栈的数据最先被弹出。自动管理:大多数编程语言和操作系统会自动管理堆栈的分配和释放,程序员不需要手动操作。快速访问:由于堆栈的操作(如压栈和弹栈)非常简单,因此访问速度较快。

qq_54177358的博客 2196

UCOS-III任务堆栈溢出检测及统计任务堆栈使用量的方法

UCOS-III任务堆栈溢出检测及统计任务堆栈使用量的方法

stephenbruce的博客 2252

操作系统课程中内存里面堆和栈的区别

操作系统课程中内存里面堆和栈的区别

yangkuiwu的博客 2658

操作系统中的堆栈的经典解释

非常经典的关于操作系统中堆栈的解释,注意不是数据结构中的堆栈,不要下载错了~~

操作系统,堆栈(stack),堆(heap),详解

/* 在学习了关于系统堆和栈的一些原理后,发表一下自己的看法与理解,希望能帮助到其他人。(红色为重点)*/ 一 首先介绍下堆和堆栈(堆栈)的是什么,区别是什么? 注意,其实堆栈本身就是栈(stack)。通俗易懂说,堆栈==栈, 堆==堆(heap) 1.堆:什么是堆?又该怎么理解呢? 答:1,堆(heap)是一种数据结构,堆控制一段自己的存储空间,叫做堆空间。 2...

qq_42034205的博客 3万+

最全卷积总结篇(分组、深度可分离、空洞、转置等)

分组卷积(Group Convolution)是一种卷积操作方式,它最早在AlexNet中引入,并在深度学习中被广泛使用,尤其是在高效模型设计(如MobileNet和ResNeXt)中。分组卷积通过将输入特征通道分为若干组,并在每组内单独进行卷积操作,可以减少计算复杂度和参数量,同时有效利用模型的结构特性。分组卷积的工作原理通道分组:输入特征图的通道图为C_in,输出特征图的通道数为C_out,将每组的C_in和C_out分为G组,每组的通道数为C_in/G和C_out/G。组内卷积。

qq_44815135的博客 4218

Microapp 接入vite子应用

MicroApp接入vite版本,干货满满,手把手步骤说明,加上报错说明,赶紧上车!

outsider76557的博客 4658

【操作系统】关于堆栈的那些事

堆栈是编程中很重要的概念,相信很多人也跳过坑,然后解决之后,继续跳坑。想整理堆栈的概念很久了。最近看了程序员自我修养,就一起整理一下吧。 本文将从几个方面学习一下堆栈 堆栈概念 进程,线程概念 堆栈分配 1. 堆栈概念 在32位系统,内存的寻址可以达到4G(2^32)。 理论上,用户可以使用一个32位的指针访问任意内存地址。 int a = 3; int * p = &a; s...

qq_43145072的博客 1512

斯坦福HumanPlus机器人核心技术解析:从HST强化学习框架到HIT模仿学习的实现路径

本文深入解析了斯坦福HumanPlus人形机器人的核心技术实现路径。其核心在于HST强化学习框架与HIT模仿学习架构的协同:HST作为“小脑”,通过rsl_rl框架在仿真中训练稳健的低级运动控制;HIT作为“大脑”,基于改进的Transformer架构学习高级任务规划。文章详细拆解了从算法原理、代码实现到硬件部署的全流程,为复现这一前沿机器人系统提供了实战指南。

weixin_29082143的博客 281

银河麒麟操作系统中设置进程堆栈大小的方法

在银河麒麟操作系统中,进程的堆栈大小是一个重要的系统参数,它决定了程序可以使用的堆栈内存的最大值。堆栈主要用于存储局部变量、函数调用等信息,对于某些需要大量堆栈空间的程序来说,调整堆栈大小是优化系统性能的一个重要手段。本文将介绍如何在银河麒麟系统中临时和永久地修改进程的堆栈大小。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 1万+

别再调参了!用Simulink手把手教你搞定FOC电机速度环PI控制器(附模型下载)

本文详细介绍了如何使用Simulink搭建FOC电机速度环PI控制器,通过模最优准则和系统化调试方法,避免传统手动调参的繁琐过程。文章包含从传递函数推导到参数自动整定的完整流程,并提供了实战调试技巧与异常处理指南,帮助工程师快速实现电机控制系统的稳定运行。

weixin_42519985的博客 413

手把手教你用STM32实现三相永磁同步电机FOC控制(附代码)

本文详细介绍了基于STM32的三相永磁同步电机(PMSM)FOC控制实现方法,涵盖硬件设计、软件架构、参数调试及完整代码解析。通过磁场定向控制(FOC)算法,实现高效精准的电机控制,适用于工业自动化、电动汽车等领域。文章还提供了硬件选型建议、电流采样方案对比及PID参数整定技巧,助力开发者快速掌握FOC控制技术。

weixin_29168675的博客 96

通过TCP/IP堆栈特征探测远程操作系统

本文主要讨论如何通过探测远程主机的TCP/IP堆栈来收集宝贵的主机系统。首先讲述几种没有包括堆栈探测技术的“传统”的主机操作系统扫描方法。接着是现在较为常见的堆栈特征扫描工具的基本原理。然后讨论一些能使远程主机“在不知不觉间”泄露其信息的技术。最后主要是nmap扫描工具的一些实现细节。动机我想谁都已经非常清楚知道远程主机操作系统有多么重要,因此这里只是作一简单叙述。首先最有用的一点在于绝大多数安全

4488

揭秘Outlook/QQ邮箱伪造:如何利用Unicode编码绕过SPF检测

本文深入剖析了利用Unicode编码进行邮件显示名伪造的攻击手法,揭示了攻击者如何通过插入零宽字符等特殊编码绕过SPF检测,使邮件在Outlook、QQ邮箱等客户端中看似来自可信发件人。文章通过Python代码示例演示了伪造过程,并提供了从用户自查到管理员部署DMARC策略的多层次防御建议。

weixin_29063035的博客 332

揭秘进程堆栈:操作系统如何分配专属内存空间

本文用形象比喻和专业技术流程,生动解释了操作系统如何为新进程分配堆栈空间。通过"公司账本"和"员工办公桌"的比喻,说明堆栈是进程的专属工作记录区。技术流程详细描述了堆栈空间的分配、指针设置、内容初始化等步骤,并配以内存地址示意图。最终强调堆栈的独立性保证了进程的安全运行。全文将复杂的技术概念转化为易于理解的日常类比,帮助读者形象化理解操作系统的堆栈管理机制。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 302

【文献笔记】ICCV 2021 | Point Transformer

作者提到,特别适合点云处理,因为自注意力机制是的核心,本质上就是一个集合算子:它对输入元素具有顺序不变性和数量不变性3D点云是无序的,即使改变点云txt文件中的点顺序也不会有任何影响。自注意力机制天然具有排列不变性,因为它通过对所有"点对"的关系进行建模来处理输入,而不依赖于任何特定的输入顺序点云数据通常覆盖了3D空间中的对象或场景,理解这些数据需要捕捉点与点之间复杂的空间关系。自注意力机制能够有效的捕捉这些关系,因为它为每个"点对"赋予一个。

m0_55908255的博客 965

996引擎 - 读写变量性能测试

单轮100万次读写,取3轮平均耗时(毫秒),有效读取率均为100%,数值越小性能越优。

灵台方寸山斜月三星洞 244

堆栈统计知多少?(内存泄漏、栈溢出、堆栈溢出,堆栈统计,堆栈常见bug)

软件的越来越复杂,对堆栈的要求也越来越高了。如何统计,又如何优化?

weixin_41784289的博客 2058

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

ucos ii堆栈大小检测

在使用ucos ii时经常会有疑问,这个堆栈该给多大,虽然ucos ii 自带了任务堆栈检测,但是我觉得太麻烦了,而且还会占用资源,我投机取巧的使用内存是否为0来判断堆栈是否使用过,进而检测出堆栈的最大使用量,我的这个方法能快速的检测出历史堆栈的最大使用量,你的实际堆栈大小必须大于历史最大使用量。 原理就是将任务堆栈使用static标记,这样任务堆栈数组都会被清零,使用过程中随着数据入栈(变为非...

与其用泪水悔恨昨天,不如用汗水拼搏今天 2988

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

堆栈寄存器:操作系统背后的核心引擎

堆栈寄存器(SP)是CPU中控制栈内存访问的核心组件,决定了栈顶位置,支撑函数调用、中断处理和进程切换等关键操作。在x86架构中称为ESP/RSP,ARM中为SP,始终存储当前栈顶地址。操作系统通过堆栈寄存器实现特权级隔离(用户态与内核态栈切换)、多线程支持(独立内核栈)和栈溢出保护。函数调用时SP随参数压栈、返回地址保存而变化;中断处理依赖SP保存上下文;进程切换本质是SP指针的更新。堆栈寄存器是连接硬件与操作系统的关键纽带,理解其工作原理对掌握计算机系统运行机制至关重要。

m0_72427326的博客 1065

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

【操作系统】用户堆栈与内核堆栈的区别切换

用户堆栈与内核堆栈的比较:        每个进程都有自己的堆栈,内核在创建一个新的进程时,在创建进程控制块task_struct的同时,也为进程创建自己堆栈。一个进程有2个堆栈,用户堆栈和内核堆栈;用户堆栈的空间指向用户地址空间,内核堆栈的空间指向内核地址空间。当进程在用户态运行时,CPU堆栈指针寄存器指向的用户堆栈地址,使用用户堆栈,当进程运行在内核态时,CPU堆栈指针寄存器指向的是内核

Cout_Sev 3252
上一篇: 海思android4.4 SDK编译Latin输入法
下一篇: ECM & EMM
simonjay2007
博客等级 码龄17年 104粉丝 112原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值