前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >别被谭浩强的《C程序设计》带偏了!

别被谭浩强的《C程序设计》带偏了!

作者头像
轩辕之风
发布于 2024-04-19 08:12:37
发布于 2024-04-19 08:12:37
1960
举报
文章被收录于专栏:编程技术宇宙编程技术宇宙

周末好各位,我是轩辕,最近干货有点少呀,我要检讨一下了。

今天就来跟大家分享一个干货,这是来自于一位粉丝的问题。

这位粉丝最近面试腾讯,被问到了一个问题:进程地址空间里有什么?

这个问题展开可以聊的东西非常多,从编程语言到可执行文件,从堆栈空间到虚拟内存,可以帮助面试官快速了解候选人这部分的知识储备。

而实际上,我发现对于这个问题,基本上没有人能够说得特别清楚,各种是似而非的回答:

“代码段” “静态存储区” “动态数据区” “堆栈区”

一系列书本气十足的说法,不一而足。

确实,很多同学手里那本谭浩强的《C程序设计》告诉我们,内存中不就是这样的吗?难道书上写错了?

书上写的也不算错,但它只是提出了一个非常非常简单的内存模型,实际的操作系统上的进程空间中,远比这复杂100倍。

虚拟内存

众所周知,现代操作系统采用虚拟内存的方式管理内存,虽然计算机上的内存条只有几个G,但却为每个进程营造出了一个完整的地址空间,加起来远超内存条容量的大小。

这个地址空间,在32位操作系统上是4GB大小,这是32位CPU在正常模式下能寻址的最大范围,LinuxWindows均是如此。

至于64位系统的情况则变得更加复杂,寻址范围更大。可以参考这两篇文章:

  • Linux 64位地址空间:https://www.cnblogs.com/yizhanwillsucceed/p/13578076.html
  • Windows 64位地址空间:https://www.cnblogs.com/xuanyuan/p/5260871.html

4GB,也就是4*1024*1024*1024 = 4294967294个字节。如果一个字节用一个小格子表示,那进程的地址空间就是这么多个小格子排列组成:

不过,这样子看起来有些麻烦,我们一般不这样画图,而是以4个字节为一组,画出地址空间来:

这篇文章要讨论的就是,在上面这张图中,到底有哪些内容。我们一步步填充进去,最后在文章的末尾你将会看到一个进程空间内容的全貌。

内核地址空间

首先,在进程地址空间中占据最大篇幅的当属操作系统内核空间部分。

内核空间的部分,所有进程共享,在不同的进程中,这部分内存空间映射的内存页面是一样的。

注:其实上面这句话也不是完全正确,如果你研究过操作系统内核就会知道不同进程的内核空间部分也不是完全一致的。一个最简单的例子就是在Windows操作系统上,不同用户登录同一台计算机后会产生会话session隔离,不同用户启动的进程位于各自的session中,而不同session在内核空间部分页面的映射会有差异。

内核空间部分一般位于进程地址空间中高地址区域,至于大小,在Windows 32位系统上是2GB,在Linux上是1GB

可执行文件

抛开了系统内核空间部分,接下来来看一下用户态地址空间中有哪些东西?

第一个非常重要的区域就是可执行文件所在的区域。

我们编写的程序,最终是转换成对应操作系统上可执行文件在运行,在Linux上是ELF格式,在Windows上是PE格式,比如exe。

程序运行的时候,加载器会将目标可执行文件加载到进程的地址空间中。

映射后的可执行程序所占大小可能会比文件的真实尺寸更大,这是由于内存页面对齐的原因,导致可执行文件中的不同节会通过填充0来对齐,从而占据了更大的空间。

你可能会问:那我写的Java程序、Python脚本程序呢?它们的进程空间中没有可执行文件吧?

Java程序是通过JVM虚拟机在翻译执行,主进程就是JVM的可执行文件,执行Java程序的时候,会先启动EXE/ELF格式的虚拟机,再由虚拟机加载java字节码文件执行。

Python是解释执行的脚本语言,执行Python脚本的时候,也是先启动Python的解释器程序,这也是一个EXE/ELF格式的可执行文件,再由解释器解释执行Python脚本。

其他脚本语言也差不多类似。

总之,所有程序的执行,都会有一个核心的可执行文件。

不管是Windows的PE格式,还是Linux的ELF格式,一般都会包含这几个部分:

  • 代码区:主要是程序编译后的CPU指令,所有的函数代码编译后的指令都在这里。
  • 数据区:主要是程序中定义的全局变量,static变量。
  • 常量区:咱们程序中会用到常量字符串编译后就存在这里。

可执行文件区域在进程地址空间哪个位置呢?

在早期的操作系统中,一般是在一个固定地址,比如Windows上,是在0x400000地址。但因为安全性的原因,后期的操作系统都开启了随机加载的功能,每一次程序启动加载到地址空间中的地址都可能不一样。

动态链接库

程序需要运行,光靠自己的可执行文件是不够的,还需要依赖一些动态链接库。在Windows上是DLL文件,在Linux上是so文件。

即便你编写的程序只是一个单独的可执行程序,没有指定依赖任何动态库,它仍然需要依赖操作系统的一系列动态链接库才能工作。

程序需要依靠这些系统动态链接库才能使用操作系统提供的系统调用,这是用户态进程和操作系统之间的一个中间层。

在Windows上,可以通过ProcessExplore,看到一个进程中加载了非常多的动态链接库。

在Linux上,可以通过pmap命令查看一个进程中的动态链接库。

和可执行文件的加载类似,现代操作系统加载动态链接库的地址一般都不固定,而是随机的。

线程栈

栈是程序执行过程中非常重要的一个东西,程序执行时的局部变量,函数调用时传参、返回地址这些东西都是存储在栈中的。

很多同学都知道程序执行会用到栈,但又经常弄错,比如有两个很多人容易弄错的点。

1、堆栈

很多人经常把“堆栈”两字挂在嘴边,但“堆”和“栈”其实是两个东西。

2、栈不止一个

栈不是程序所有,而是线程所有,如果一个程序运行后开启了多个线程,则每一个线程都会有一个自己的栈。

所有线程的栈都在进程的地址空间中,具体位置是由操作系统内核在创建线程的时候确定的,用户程序无法控制。

进程堆

说到栈,那就必然离不开它的好基友——堆。

堆大家应该不会陌生,C语言中malloc、C++中的new都是在堆区域中分配内存。

堆是一大块内存,由C和C++语言的运行时库Runtime初始化时向系统申请的,后续调用malloc和new的时候再去堆中分配。

不同于前面介绍的部分,堆这个东西是语言层面的东西,理论上完全可能存在一个没有动态内存分配的语言写出的程序,进程地址空间中就没有堆。

不过这样貌似也不行,因为Windows和Linux的动态库都是用C语言写成的,它们也会用到堆。

除了栈可能有多个,堆其实也是可以有多个。

文件映射

除了栈和堆,我们在编程中,还经常用到共享内存、内存文件映射、或者直接使用VirtualAlloc/mmap分配内存等操作,这些操作,是直接在进程地址空间中的空余部分,划出的一块单独区域。他们也是地址空间中经常出现的部分。

最后推荐一个神器:VMMap,用来查看进程地址空间中所有内容的占用情况。

软件开发过程中,常用来定位程序问题,观察进程内存空间使用情况,比如观察线程栈暴涨,则程序有可能陷入了死循环,无限递归,如果堆内存暴涨,则很有可能有内存泄露。

在软件漏洞安全研究中,也常用来分析程序被攻击的原理。

今天的分享就是这样,现在,你知道进程的内存空间里都有什么了吗?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程技术宇宙 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
vue cli3 build 区分测试环境和生产环境
三、vue.config.js 修改 outputDir:process.env.outputDir,
tianyawhl
2021/04/01
1.2K0
vue cli3 build 区分测试环境和生产环境
webpack从零搭建开发环境
为了方便也可以这么写,使用 npm run 命令这个命令执行的时候默认会把 node_modules 的.bin 文件放到全局上,执行之后销毁npm run buildnpm run dev
小丑同学
2020/09/21
1.3K0
VUE项目使用.env文件配置全局环境变量
注意:属性名必须以VUE_APP_开头,比如VUE_APP_URL VUE_APP_XXX
用户4464623
2020/09/10
3.1K0
uni-app的多环境部署配置
记录下如何对uni-app项目进行多环境打包部署改造 # 环境区分 官方文档说明: 开发环境和生产环境 uni-app 可通过 process.env.NODE_ENV 判断当前环境是开发环境还是生产环境。一般用于连接测试服务器或生产服务器的动态切换。 在HBuilderX 中,点击“运行”编译出来的代码是开发环境,点击“发行”编译出来的代码是生产环境 # 解决方案 使用基于vue-cli命令行方式创建项目 添加必要的环境变量, VUE_APP_ 起始,例如 VUE_APP_BASE_API 即在
薛定喵君
2021/05/18
3.8K0
【前端配置篇】vue项目之.env系列文件配置详解:.env文件配置全局环境变量
vue 会根据启动命令自动加载相对应的环境配置文件。vue是根据文件名进行加载的,所以上面说“不要乱起名,也无需专门控制加载哪个文件”
江一铭
2022/06/17
19.6K0
【前端配置篇】vue项目之.env系列文件配置详解:.env文件配置全局环境变量
基于 Vue-cli 3x的项目部署
项目中涉及使用了 vue-cli 3x脚手架、自动化部署工具jenkins、nginx等。
树酱
2020/07/03
8050
vue3+element-plus+router+vuex+axios从零开始搭建(2)
vue-cli 3.0x与vue-cli 2.0x最主要的区别是项目结构目录精简化,这也带来了许多问题,很多配置需要自己配置,
solate
2021/06/21
1.5K0
实战总结 Vue 学习看这一篇就够了
当前总结是本人在业余学习与实践过程后的总结与归纳,旨在检验自己的积累,也方便忘记时查阅,同时也希望能帮助那些这方面知识匮乏的同行门,总结是基于 vue2.x,vue-cli3.x ,主要记录些,vue 常用的指令、事件,监听、数据绑定、过滤器、组件、动画、vuex,vue-router 等日常工作中时常用到的东西,也有些常用的插件和开发工具的介绍与使用,以及部分性能优化的建议与实践,如有不对,或不足的地方,也请各位大神,指出来,学习学习。
网罗开发
2021/02/26
1.9K0
Vue CLI中使用webpack的多模式和环境变量
在vue项目中我们根据不同的环境去打不同的包, 如测试环境,开发环境, 正式环境 这个时候我们可以使用webpak中的模式和环境变量来操作
拿我格子衫来
2022/01/24
7020
electron套壳vue2项目
最近lender提了个需求,说最近项目可能要变动一下,把网页端变成桌面端,小手一挥,博主就开始库库的找。奈何网上教程一大堆,但是没找到一个对版的,不是安装过程有错,就是执行命令过程失误。一个教程文章得搜五个报错文章,虽然最终我做出来噜,但是很费劲,所以这篇用来总结一下。
刘小胖
2024/04/10
5092
electron套壳vue2项目
react配置生产环境和测试环境地址
写在前面 之前一直写关于vue的文章,经常看我文章的可能从上篇文章就知道了我已经不写vue了,以后就写react了,会持续更新,今天说一下我搭建框架的时候配置不同环境的步骤,大家可以借鉴以下,也可以自己搞一下! 在项目根目录创建两个环境文件 .env.development .env.production 文件内容 .env.developemnt REACT_APP_BASE_URL = 'https://test.com' REACT_APP_ENV = 'development' .env.pr
何处锦绣不灰堆
2021/05/06
2.8K0
Vue开发项目过程中环境变量的配置(vite、vue3、ts)
项目开发过程中,至少会经历开发环境、测试环境和生产环境(即正式环境)三个阶段。不同阶段请求的状态(如接口地址等)不尽相同,若手动切换接口地址是相当繁琐且易出错的。于是环境变量配置的需求就应运而生,我们只需做简单的配置,把环境状态切换的工作交给代码。
HelloWorldZ
2024/05/24
6320
Vue开发项目过程中环境变量的配置(vite、vue3、ts)
vue-cli3项目搭建配置以及性能优化
在之前的开发中主要用的是vue-cli2,最近空闲时间比较多,接下来有新项目,本着偷懒的本能,自己打算搭建一个基础包以备后期开发应用,并对其进行性能优化和配置
青梅煮码
2023/03/13
1.7K0
vue-cli3项目搭建配置以及性能优化
vue3+ts+element-plus 后端管理系统系列一(简介)
vue3-composition-admin 是一个管理端模板解决方案,它是基于vue3,ts和element-plus,项目都是以composition api风格编写。
星宇大前端
2021/02/02
10.3K1
Vue+ElementUI 搭建后台管理系统(实战系列八)
使用ElementUI已经有一段时间了,在一边上手开发后台管理系统的同事,也记录了一些笔记,一直都没有时间将这些零零散散的笔记总结起来,整理成一个比较系统详细一点的教程,可以留着以后来看。
王小婷
2021/11/24
7760
Vue+ElementUI 搭建后台管理系统(实战系列八)
vue vue-clie多环境配置
键:环境名,在运行命令的时候使用,如:npm run serve01就是执行该键所对应的值命令 值:vue-cli-service命令;serve表示是运行还是打包,serve表示是编译运行,build则是进行打包;--mode serve_01表示环境的模式名字,在创建配置文件的时候作为区分。
小蔚
2021/03/11
7380
vue    vue-clie多环境配置
vite开发环境、生产环境配置
一个项目可能会有开发版本、上线版本、测试版本等等多个版本,不同的环境会有不同请求api接口,就需更改一些基本配置,这时候就显得很麻烦,所以这里就使用了环境变量。我们只需做简单的配置,把环境状态切换的工作交给代码。
小蔚
2023/11/03
2.4K0
vite开发环境、生产环境配置
CROSS-ENV不同环境配置
项目背景 为了适应h5环境搭建需求,需要动态配置开发,测试,生产三种对应域名及其及打包命令。使用cross-env可以让配置环境更加清晰明了还好管理。 简介 cross-env的作用是不需要全局配置NODE_ENV在scripts脚本中修改NODE_ENV的值从而实现不同环境中proccess.env.NODE_ENV的不同,而config的工作原理就是基于NODE_ENV这个值的,所以推荐两者结合使用。 安装 cross-env
我不是费圆
2020/10/09
4.9K0
vue-cli3分环境打包,不压缩包大小问题
地址: https://cli.vuejs.org/zh/guide/mode-and-env.html
王念博客
2019/07/25
2.7K0
vue cli3 开发环境与生产环境配置(一)
初始化项目 vue create vue-asgisn cd vue-asgisn npm run serve 一、 已经初始化项目后, 为了开发方便以及维护, 新增一些文件夹 - store
yangdongnan
2019/04/22
5.8K0
vue cli3 开发环境与生产环境配置(一)
相关推荐
vue cli3 build 区分测试环境和生产环境
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档