后端技术面试 38 讲
李智慧
同程艺龙交通首席架构师,前 Intel& 阿里架构师,《大型网站技术架构》作者
37373 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 46 讲
不定期加餐 (1讲)
后端技术面试 38 讲
15
15
1.0x
00:00/00:00
登录|注册

01丨程序运行原理:程序是如何运行又是如何崩溃的?

解决系统变慢和崩溃的手段
线程安全问题
多线程并发执行
线程状态
进程状态
CPU分时共享技术
进程的组成
程序加载到内存
代码编译
系统为什么会变慢,为什么会崩溃
一台计算机如何同时处理数以百计的任务
程序是如何运行起来的
思考题
程序是如何运行又是如何崩溃的?

该思维导图由 AI 生成,仅供参考

软件的核心载体是程序代码,软件开发的主要工作产出也是代码,但是代码被存储在磁盘上本身没有任何价值,软件要想实现价值,代码就必须运行起来。那么代码是如何运行的?在运行中可能会出现什么问题呢?

程序是如何运行起来的

软件被开发出来,是文本格式的代码,这些代码通常不能直接运行,需要使用编译器编译成操作系统或者虚拟机可以运行的代码,即可执行代码,它们都被存储在文件系统中。不管是文本格式的代码还是可执行的代码,都被称为程序程序是静态的,安静地呆在磁盘上,什么也干不了。要想让程序处理数据,完成计算任务,必须把程序从外部设备加载到内存中,并在操作系统的管理调度下交给 CPU 去执行,去运行起来,才能真正发挥软件的作用,程序运行起来以后,被称作进程
进程除了包含可执行的程序代码,还包括进程在运行期使用的内存堆空间、栈空间、供操作系统管理用的数据结构。如下图所示:
操作系统把可执行代码加载到内存中,生成相应的数据结构和内存空间后,就从可执行代码的起始位置读取指令交给 CPU 顺序执行。指令执行过程中,可能会遇到一条跳转指令,即 CPU 要执行的下一条指令不是内存中可执行代码顺序的下一条指令。编程中使用的循环 for…,while…和 if…else…最后都被编译成跳转指令。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了程序代码的运行过程和可能出现的问题。首先介绍了程序是如何从文本格式的代码转化为可执行代码,并在内存中运行成为进程的。文章还详细解释了进程的内存结构和栈帧的创建过程,以及一台计算机如何同时处理多个任务的原理。通过操作系统的CPU分时共享技术,多个进程可以轮流在CPU上运行,实现了多任务处理。此外,文章还介绍了线程的概念和与进程的关系,强调了多线程开发在服务器应用开发中的重要性。文章还探讨了多线程并发执行时可能出现的线程安全问题,以及如何使用锁来解决临界区的线程安全问题。此外,还介绍了高并发系统架构方案以及软件运行和部署的规划和架构。总之,本文通过深入浅出的方式解释了程序运行的原理和多任务处理的技术,适合读者快速了解程序运行和崩溃的基本概念。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《后端技术面试 38 讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(56)

  • 最新
  • 精选
  • 斐波那契
    在java里 锁是通过cas把当前线程id刷新到对象的头信息里 在获取锁时会去头信息里拿这个信息 如果没有 则会cas刷新进去 刷新成功就获取到锁 刷新失败就表明有别的线程也在尝试刷新这个信息 在操作系统层面 有pv操作保证原子性 而pv操作也是利用cpu中原语指令 在获取锁时保证不会被别的指令打断(或被重排序)

    作者回复: 👍

    2019-11-18
    5
    103
  • Luciano李鑫
    “不管你是否有意识,你开发的 web 程序都是被多线程执行的,web 开发天然就是多线程开发。”这个会不会绝对了一些,比如go或者c++开发的没有额外创建线程的web程序呢?

    作者回复: 这样开发出来的也就不会是一个可以满足高并发的web应用😁 也就不会有我们标题提出的问题~ 这个专栏的大部分文章都试图在一篇较小的篇幅内讲完整一个较大的问题场景,这样就会有一些绝对化和理想化,后面的文章也会有类似的情况😢 这也真是我在开篇词想要表达的意图,我们在构建自己的知识体系时,不追求细节的完整和绝对的严谨,而是在大的方向上建起支撑性的知识支柱。细节的缺失和瑕疵在未来的学习和实践中完善。 当然也欢迎大家在评论中指出各种问题,有兴趣的同学参与讨论,我们在评论区就完成部分知识的深入和完善。 感谢🌹

    2019-11-18
    9
    39
  • Allen_
    有些地方可能不是很到位,欢迎补充 小结: 1. 我们平时开发出来的程序是文本格式代码,但只是在硬盘中还只是一个程序,只有加载到内存里面通过cpu执行成为进程才是发挥了程序作用。 2.进程里面有堆,栈,可执行代码和进程数据结构。 3.cpu分时共享技术进行并发操作,进程切换效率不高,所以有了线程切换 4.因为线程安全问题引入锁,不过也引入了更多造成阻塞的可能 5.线程阻塞可能是I/O,锁,网络请求,数据库链接获取 6利用分布式系统架构来减缓高并发的性能不佳

    作者回复: 清晰👍

    2019-11-18
    4
    23
  • 蚂蚁内推+v
    李老师好:我想请教下,一个JVM 是一个进程。JVM 上跑 tomcat,tomcat 可以部署多个应用?那每个跑在tomcat 上的应用是一个线程吗?那一个应用crash了,其他应用也会crash.这块感觉有点问题。不知道老师方便解释下吗?

    作者回复: JVM是一个进程;tomcat是一个框架;tomcat会启动线程处理应用请求,执行应用的代码;应用自己不能跑起来的,只能被tomcat的线程执行,应用在tomcat线程中执行时,也可以自己启动线程,并发、异步执行自己的某些计算。 tomcat会对不同应用做一些隔离,但是如果某个应用导致JVM crash,所有应用都crash。 可参考后续专栏《JVM虚拟机原理》

    2019-11-18
    2
    15
  • 雷咏
    我们用文本格式书写的程序有三种执行方式: 1.解释执行。例子是脚本语言书写的程序或类似于BASIC语言书写的程序。著名的PYTHON也属于这种情况。 2.编译执行。通常C/C++程序属于这种情况。文本格式书写的程序称之为源程序,需要编译器编译成机器语言代码,称之为可执行程序一或目标程序。 3.虚拟机执行。将文本格式的程序先编译成一种中间代码,然后由驻留在计算机中的虚拟机解释执行。例子是通常的JAVA程序。

    作者回复: 👍

    2019-11-19
    3
    12
  • 我爱布丁
    老师,看完文章,联想到两个关于协程的问题: 1. 使用协程在出现IO等待时,程序会自己调度去执行其他的(CPU)任务。理论上这样可以避免额外的IO等待导致的线程间切换。我的问题是从系统的角度上看,使用协程可以抢占到更多的CPU时间片吗? 2. 感觉系统崩溃(除人为Bug外) 主要是系统资源不足导致的。那么即使用轻量级的协程也不会变得更好。因为当协程数量过多,导致event loop过大,变慢,系统还是要崩溃的对吗?

    作者回复: 1 多个协程通过自我调度复用同一个线程,所以某个协程IO等待的时候,会导致整个线程阻塞,并不能避免线程切换。更好的做法是使用异步IO,不要IO等待。 能否抢到时间片是操作系统调度的,协程自己控制不了,但是协程利用自己更轻量级,配合异步IO等方法,可以提高运行效率,整体性能得到优化。 2 是的。但是用好协程,减少额外的线程调度切换,可以提高整体的系统吞吐能力。

    2019-11-21
    11
  • 探索无止境
    希望老师在第二节课可以谈谈上一节课留下的思考题,您是怎么理解分析的

    作者回复: 也许可以将来以彩蛋的方式专门写一篇文章讲讲~

    2019-11-19
    6
  • peter
    一直以为tomcat是一个独立的进程。根据本文所述,tomcat只是一个线程,是虚拟机进程中的一个线程。是这样吗?

    作者回复: tomcat是一个程序,被JVM加载到JVM进程中。 Tomcat的代码在JVM被执行后,可以启动很多线程。

    2019-11-24
    4
  • Heidi
    你好,想提个问题。文章中大部分知识点都掌握,但是遇到问题的时候没有从这些角度出发,只是跟着一些关联去分析问题,对遇到的问题反应比较慢。这种情况是不是知识没有成体系?那么怎样建立比较完整的知识体系呢?

    作者回复: 思考问题从问题的根源出发思考,如果在解决问题的时候现场比较乱,无法做到。事后做复盘,复盘的时候重新从根源思考。

    2019-11-20
    3
    4
  • Tobe24
    您好,老师,这节课太适合我这种新手了,这里有三个不太明白的地方,希望老师能够解惑。 问题1:CPU 分时共享技术同时执行进程的数量,取决于什么? 问题2:为什么线程切换的代价更小? 问题3:进程切换是不是必须要等到线程切换完毕后进行?如果不是,优先级是由什么决定的? 一点小建议: 有一些表达程度的词,如果能用数据举例简单说明一下,对于我们理解会更有帮助。比如2问题中,代价更小,小到什么程度,是进程切换速度的几倍? 思考题: 作为小白,我的思路是这样,锁是在线程的临界区,线程是在进程的线程栈,而 一个 cpu 同时只能运行一个进程,所以本质上都是轮流执行的……于是,只要保证在获取锁的时候,锁不在正在获取或已经被获取的状态即可,进而推断线程中会有一片内存区域用来存这些状态信息。 😂不知道这个思路对不对。 最后谢谢老师。

    作者回复: 1 取决于CPU的核数 2 线程比进程占据的资源少,切换代价小,而且进程内线程可能执行相同的代码,切换线程后也许还可以复用CPU cache数据 3 线程切换和进程切换只依赖CPU是否空闲,和线程进程彼此没关系 PS,上面回复内容其实我也没有确切的资料证实,我是根据第一性原理推导出来的,我觉得仅根据专栏文章内容就可以推导出来,我希望你也可以自己分析推导,这样获得的知识会更加稳固

    2019-11-20
    3
    4
收起评论
显示
设置
留言
56
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部