21 | 运行时机制:突破现象看本质,透过语法看运行时
21 | 运行时机制:突破现象看本质,透过语法看运行时
讲述:宫文学
时长15:51大小14.52M
程序运行的环境
1. 关注 CPU 和内存
2. 程序和操作系统的关系
程序运行的过程
1. 程序运行的细节
2. 从全局角度看整个运行过程
课程小结
一课一思
赞 9
提建议
精选留言(16)
- 鹏置顶2019-10-25宫老师讲的真好!一直以来,都有一种强烈的信念!要学编译原理,要学这种在日新月异的信息技术领域里“亘古不变”的技术原理,以不变应万变。上半年学习了极客时间出的“深入浅出计算机组成原理”,在这一节正好排上用场,对程序运行时机制有了更深入的理解。
作者回复: 对的。 计算机的组成原理、编译器的基本架构等等内容,其实半个世纪也没有太大的变化,是比较稳定的。并且,真正做一些深入的工作的时候,这些知识仍然非常有价值。
8 - Gopher2019-10-09写的真好,一下子就听懂了( ̄∀ ̄) 内存布局: 指令数据,分而治之; 自下而上,由静至动; 栉比鳞次,序从中来。展开
作者回复: 你不光代码写得好,文采也很好。 新东方的三驾马车之一的王强说到,好的代码就像诗歌一样优美。写完代码要站在远处欣赏一下 :-)
12 - 刘強2019-11-05文章里说操作系统还会自动维护栈。 但我觉得栈的维护是有程序或者编译器来维护的。操作系统只是给程序(进程)分配了栈的起始地址而已,剩下的进栈和出栈操作,都是预先编译好的push和pop指令来完成的。不知理解的对不对。
作者回复: 栈这个东西,如果深入看一下,其实涉及得还挺多的。 操作系统的介入,主要原因是内存管理。因为你的程序所使用的内存,并不是物理内存,都是虚拟出来的。在你使用栈的时候,操作系统要帮你把逻辑的内存映射到物理的内存上去。只不过这个过程对程序是透明的。是CPU和操作系统之间协作完成的。 具体细节是:当你push一个新的变量到栈里的时候,如果超出了当前可用的物理内存,CPU会产生一个page fault(缺页错误),操作系统这个时候介入,调度一页新的物理内存过来。 你可以查看Intel的手册,看看push指令的说明,里面有介绍。关于page fault,你可以参考https://en.wikipedia.org/wiki/Page_fault 当然,如果你的程序直接运行在裸机上,没有使用操作系统,那就没有操作系统什么事了。直接在裸机上编程叫做bare metal programming,在有些领域很有用。 总结起来,栈的管理,与CPU、内存和你的代码都有关。
共 2 条评论8 - wolfie2020-12-13“控制链接”和“上一帧的%rbp的值”两者分列返回地址的两边,它们是怎样的关系?
作者回复: 控制链接通常是指向上一级作用域的函数对应的栈桢,用于查找上一级作用域中变量的值,它不一定是前一个栈桢。 比如,有两个函数,foo和bar,他们都是在全局作用域中声明的,而在foo里调用了bar。那么,bar的控制链接是指向全局作用域(的栈桢),可以访问全局变量,而不是指向foo(的栈桢)。
共 2 条评论6 - sunbird2020-11-21一节一节,看的根本停不下来。看过才发现,自己根本不会计算机。比MOOC上那些顶尖名牌大学的教授讲的好太多了!!! 有几个问题还是想的不太明白,麻烦宫老师在***有时间的时候***帮忙解惑一下,不胜感激。 1.这个栈是操作系统维护的栈吗? 2.这个栈和数据结构中的栈有什么区别? 3.这个栈是每个程序一个,还是所有的程序共用一个? 4.这个栈是和进程绑定的吗? 5.多线程的时候,每个线程都有自己的方法栈,和这个栈是一个吗?如果不是,他们之间有什么区别? 6.栈为什么是高地址向低地址的延伸?栈顶在高地址还是低地址?栈寄存器指向的是栈顶吗?展开
作者回复: 谬赞了! 回答一下你的问题: 1.是的,栈是操作系统维护的,所以会降低程序维护内存的负担。但缺点是函数退出后栈里的内存就自动收回,这点是跟堆的区别。 2.数据结构中的栈是一个普遍的概念,可以用在很多地方。内存管理是栈的一个具体应用。 3.在现在操作系统中,是每个线程一个栈。如果一个进程里面有多个线程,那就有多个栈。 另外,如果程序是支持协程的,有些实现机制也会给协程提供单独的栈,用来维护协程的状态。但协程的栈一般是由程序的运行时或库来支持的,而不是由操作系统来维护的。 4.同上,栈是跟线程绑定的。 5.同上,每个线程有自己单独的栈。 6.栈从高地址到低地址延伸,这个时候栈顶是低地址。对于这个问题,没有什么特别的道理,只是一个设计决定而已。并且,并不是所有的架构都这样设计,有的设计恰好是反向的。栈寄存器的设计也是跟具体架构相关的。对于比较新的x86架构来说,我们一般只需要一个指向栈顶的栈寄存器即可。但,由于调用约定通常要向下兼容,所以生成的程序通常也要用到一个寄存器指向栈底。 对于上述问题,我想额外指出几点: 1.上述具体实现,跟CPU架构和操作系统二者都有关系,不是死的。编译器在实现的时候,要生成针对具体架构的代码。不要认为这些都是一成不变的。 2.在《编译原理实战课》中,对于运行时有更多的介绍,比如栈和线程的关系,协程的机制等等。你可以参考。
5 - 吴小智2020-01-08太赞了,老师一文道破计算机专业本科生四年需要学的 70% 专业领域的知识,底层知识扎实很重要。
作者回复: 谬赞了。 不过学习编译原理,确实会用到计算机学科的多方面的知识,如形式语言、数据结构和算法、计算机组成、操作系统等。这也不奇怪,因为你要让一门语言跑起来,就是要涉及方方面面。
5 - 曾经瘦过2019-10-09使用的java 语言。java是运行在jvm虚拟机里面的,是便以为jvm所需的机器码 基本的过程和这个是差不多的。看了这一篇专栏之后 发现基础知识的用处真的很多,操作系统 组成原理 用处真多。
作者回复: 对呀。既然学计算机嘛,就搞到根本上去,心里会比较踏实。而且说实话,基础原理并不多,也不易变。反倒上层各种类库、框架,层出不穷,天天更新。这两头哪边学起来更辛苦,真不一定!
4 - westfall2020-05-21像js这种非编译性语言又是怎么跑起来的呢?
作者回复: 通常,是要通过一个解释器来执行。而解释器执行的一般是中间代码,比如java和python的字节码。 还有一种情况,就是把js快速编译成机器码,然后执行。因为是快速编译,所以不够优化,代码体积也比较大,但好处是编译时间很短,可以马上跑起来。如果一段代码经常被执行,就意味着这个热代码,那么就进行优化编译,产生更好的代码。这就是早期JavaScript引擎做编译的流程。但最新的v8引擎,采用的是一个解释器(ignition)加一个优化编译器(turbofan)的结构,看上去跟JVM很像,都是一个解释器加一个优化编译器。 我在第二季《编译原理实战课》的运行环境这一讲,增加了栈机和寄存器机这两种虚拟机的介绍。另外,也有对v8编译器的分析。你可以去看看。
3 - 阿辉2021-04-15老师说的真好,通过老师的讲解,运行时的机制主要是操作作系统系统级别,那编译器起的主要作用是?我们通常所说的runtime到底指的是什么?和vm,engine之类的有啥区别啊?
作者回复: 当我们谈论一门语言的时候,通常三个组成部分是必不可少的:编译器、运行时和标准库。此外,一般还要加上一些工具,比如模块管理工具、调试工具等等。 运行时,顾名思义,就是你编写的程序在运行的时候所需要的那些软件。这个定义比较泛,所以在Windows系统中,把一些标准库也称作运行时,因为确实是在Windows上运行软件所必须的。 而虚拟机,则是比较复杂的那种运行时,典型代表是HotSpot虚拟机和V8虚拟机,它们为程序的运行、内存管理、并发等都提供了支持,程序可以无缝地在解释执行和运行本地代码之间切换、适时地启动自动编译机制等。 你可以看出,这种级别的运行时和操作系统的功能有很多相似之处。比如,要做好内存的管理,其实你需要对操作系统的内存管理也了解得比较深,并使它们二者良好的配合。并发也是如此。
2 - 微秒2020-03-16老师你好,想问下你在文中说的静态数据期的地址在编译时就确定,这里的地址是虚拟地址,还是实际内存地址。
作者回复: 应用程序能够看到的地址,都是操作系统虚拟出来的,除非你直接运行在裸机上。
2 - upon you2022-06-09老师好,请问如果函数调用返回了一个值,但是这个值没有被使用,那么这个值怎么处理呢? 比如下面的形式 while(1) { get(); // return 100 dispatch(); }展开
- Join2021-11-06太通俗易懂啦,最近刚看完龙书的运行时,再看这节,感觉在复习
- 淡2020-04-26宫老师,你好。文章中对于函数返回后,写到: ”但是在这个例子中你会看到,即使返回了 bar 函数,我们仍要访问栈顶之外的一个内存地址,也就是返回值的地址。“,这里没太明白,bar函数返回后,返回值地址还在bar栈中,因为外层调用函数要用变量(也可以理解为外层栈空间)接受这个返回值,接受完了是不是就可以释放了?是因为有其他比较特殊的场景如外层异步调用内层函数?共 1 条评论
- 宋健2020-04-04老师讲的真不错,上学期学校正好学了汇编,也做过实验,果然感觉后端要比前端好理解很多呀
作者回复: 谢谢肯定! 可是很多同学都会觉得后端更难呢:-)
- 风2019-10-19怎么没提push和pop呢
作者回复: 在22讲,汇编语言的部分就有。
- D2019-10-10有些汇编的语法和上面的是反着的,比如 指令:寄存器 ,源操作数/地址
作者回复: 是的。我们用的都是GNU汇编的语法。第22讲正式讲汇编的时候特别做了说明。看看是不是在21讲提到汇编时也注释一下。