什么是“运行时”?

627

我听说过像是“C Runtime”、“Visual C++ 2008 Runtime”、“.NET Common Language Runtime”等东西。

  • 到底什么是“runtime”?
  • 它由什么构成?
  • 它如何与我的代码交互?或者更准确地说,我的代码如何被它控制?

在Linux上编写汇编语言时,我可以使用INT指令进行系统调用。那么,难道运行时就是一堆将低级函数封装为更抽象和高级的函数的预制函数吗?但这似乎更像是库的定义,而不是运行时的定义?

“运行时”和“运行时库”是两个不同的东西吗?

添加1

最近,我在思考“运行时”与所谓的虚拟机(例如JVM)是否有共同之处。以下是引发此想法的引文:

这种编译过程足够复杂,可以分解为几个层次的抽象,通常涉及三个翻译器:编译器、虚拟机实现和汇编程序。 --- 计算机系统的构成要素(引言,通往硬件之路)

添加2

书籍《专家C编程:深入C语言的秘密》中的第6章“运行时数据结构”对这个问题是一个有用的参考。

添加3 - 7:31 AM 2/28/2021

在了解处理器设计后,我对计算机整个系统有了一些看法。整个计算机系统是由多个抽象层次组成,从基本的晶体管一直到运行程序。对于任何第N层的抽象层,它的运行时即为其下方的第N-1层的抽象层。而第0层抽象层则是上帝所赐。


2
运行时包括运行时库和一些控制代码以及一些状态(由操作系统提供)。 - Martin York
88
很棒的问题,我一直对此存疑。 - contactmatt
4
我在另一个姊妹网站上找到了另一篇可能有用的文章:http://programmers.stackexchange.com/questions/294346/c-runtime-and-runtime-linking - CloudyTrees
我总是把它想象成一个降低基础架构的沙盒。在Unix工具包上,你有任务管理器/或进程,所有低级GUI库等等。所有这些都是运行时的一部分。这些是事物构建的基础。 - JGFMK
2
无法赞同更多上次的更新。 - Kaoutar
2
无法赞同更多上一次的更新。 - undefined
14个回答

402

Runtime(运行时)指的是在程序运行时执行的软件/指令,特别是那些你没有明确编写但对代码正确执行必不可少的指令。

低级语言如C语言几乎没有(如果有也很少)运行时。而像Objective-C这样允许动态消息传递的复杂语言则有更加广泛的运行时。

您说得对,运行时代码是库代码,但是库代码是一个更通用的术语,描述任何库生成的代码。运行时代码具体指实现语言本身功能所需的代码。


2
我认为“特别是那些你没有明确编写的指令”并不是一个有用的区分;无论是你自己编写的代码行,还是编译器从其他人编写的库中引入的代码行,都与编译时和运行时的区别无关。 - Ben Wheeler
3
@BenWheeler 这个答案并不是关于“运行时”(与编译时相反)的。请注意,在OP的问题和所有这些答案的背景下,“运行时”和“运行时间”是不同的,尽管人们只是用相同的术语“运行时”来表示这些不同的概念。实际上,用户(使用语言的开发人员)并没有编写运行时,它是语言实现的一部分。 - starriet

140

Runtime是一个通用术语,指的是您的代码运行的任何库、框架或平台。

C和C++运行时是函数集合。

.NET运行时包含一个中间语言解释器、垃圾回收器等。


4
C++标准库不仅包含函数。根据Matt Ball的说法,C和C++的“运行时”是运行时库,.NET运行时既是运行时库又是运行时系统。 - smerlin
1
我的问题是静态库也是运行时的吗?我猜这个术语主要用于共享对象,不是吗?考虑Linux中的libc。那么平台和框架呢?它们也被分解成库了吗? - Amir Zadeh
11
但是我的代码如何在任何“库、框架或平台”上运行呢?它应该在 CPU 或其他处理单元上运行。你能否提供更详细的说明以进行进一步澄清? - n611x007
C和C++运行时是函数集合。 -> 什么样的函数? - Koray Tugay
4
标准库中的函数,例如 coutprintf - SLaks
显示剩余3条评论

91
根据维基百科:运行时库/运行时系统
在计算机编程中,运行时库是编译器使用的特殊程序库,用于在计算机程序运行时实现编程语言内置函数。这通常包括输入输出函数或内存管理函数。
一个运行时系统(也称为运行时系统或仅称为运行时)是旨在支持使用某些计算机语言编写的计算机程序的执行的软件。运行时系统包含基本低级命令的实现,还可以实现更高级别的命令,并可能支持类型检查、调试甚至代码生成和优化。运行时系统的一些服务可通过应用程序编程接口访问,但其他服务(如任务调度和资源管理)可能无法访问。

关于你的编辑,“runtime”和“runtime library”是同一件事情的不同名称。


91
维基百科不是引用名言的好来源。它是开始寻找权威来源的好地方,但本身不应被认为是权威的,因此从中引用不可靠。(根据维基百科创始人沃尔斯先生的说法) - Martin York
6
第一句话中的"during the runtime"是指什么?一个容易[误]理解的解释可能是: "当程序执行时,编译器并行使用库(用于自身)来实现(即在运行时生成额外的代码)语言规范所“承诺”的函数。"这可能是错误的和/或很容易被运行时系统的定义所扭曲。 - n611x007
2
继续Loki离开的地方,尤其是当这两篇文章都没有提供任何参考资料时(这不是引用,只是我认为最好说一下)。 - arsaKasra
1
@MartinYork,百科全书不仅不具有权威性,而且它侧重于文档记录而非解释。这两者可能存在很大的差异。 - Roy Prins

88

运行时执行环境是语言实现的一部分,用于在运行时执行代码;实现的编译时部分在C标准中称为翻译环境

例子:

  • Java运行时由虚拟机和标准库组成。

  • C语言常见的运行时包括加载器(是操作系统的一部分)和运行时库。运行时库实现了C语言中编译器未构建到可执行文件中的部分;在托管环境中,这包括大部分标准库。


6
谢谢,我认为这是该主题中最好的答案。 - Koray Tugay
5
我很欣赏“执行环境”的命名,但我认为仅仅使用“运行时”作为前者的别名是一个不好的想法(根据我的观察,许多程序员都这样做),“运行时环境”更加准确。我同意@MichałTrybus的看法,“运行时”意味着“程序运行的时间”。 - WloHu
1
什么是“托管环境”?我搜索了一下,但只找到了一些与网络相关的东西。 - starriet
回答自己的问题:请参见此评论。实际上,C标准描述了两种类型的C环境-"自立"和"托管"-在托管环境中,标准中描述的函数被定义为可用。在嵌入式系统中,C环境通常是自立的,因此您可能没有库例程,或者您可以避免使用某些库例程并使用自己的替代方案。 - starriet
在答案中添加编译时实体使其变得非常清晰。将"运行时"与"编译时"进行比较,毫无疑问地说明了运行时是什么,因为编译是显而易见的。这是一个很好的答案。我甚至把它写在纸上了。非常感谢你。 - undefined

71

我对其他答案并不满意,它们对我来说太过模糊和抽象。我更喜欢通过故事进行思考。以下是我对更好答案的尝试。

一个BASIC的例子

假设现在是1985年,你在一台Apple II上编写了一个简短的BASIC程序:

] 10 PRINT "HELLO WORLD!"
] 20 GOTO 10

到目前为止, 你的程序只是源代码. 它还没有运行,我们可以说它没有涉及任何 "运行时".

但现在我要运行它:

] RUN

实际上是如何运行的?它如何知道将字符串参数从PRINT发送到物理屏幕?我在代码中没有提供任何系统信息,而PRINT本身也不知道我的系统。

相反,RUN本身就是一个程序——它的代码告诉它如何解析我的代码,如何执行它,并如何向计算机操作系统发送任何相关请求。 RUN程序提供了充当操作系统和源代码之间层的“运行时”环境。操作系统本身作为这个“运行时”的一部分,但通常我们在谈论像RUN程序这样的“运行时”时并不打算包括它。

编译和运行时类型

已编译的二进制语言

在某些语言中,必须在运行之前编译源代码。一些语言将您的代码编译成机器语言,您的操作系统可以直接运行它。这个编译出来的代码通常称为“二进制文件”(尽管每种其他类型的文件也都是二进制的 :)

在这种情况下,仍然涉及到最小的“运行时”——但是该运行时由操作系统本身提供。编译步骤意味着许多会导致程序崩溃的语句在代码运行之前被检测到。

C就是这样一种语言;当您运行C程序时,它完全能够向操作系统发送非法请求(例如,“让我控制计算机上所有的内存,并抹掉它们”)。如果遇到非法请求,通常操作系统只会杀死您的程序,并且不告诉您原因,并将该程序在被杀死时的内存内容转储到一个相当难以理解的.dump文件中。但有时候您的代码具有一个非常糟糕的命令,但是操作系统不认为它是非法的,比如“删除该程序正在使用的任意一位内存”的命令;那可能会导致超级奇怪的问题,很难搞清楚。

字节码语言

其他语言(如Java、Python)将您的代码编译成操作系统无法直接读取的语言,但特定的运行时程序可以读取您的编译代码。这个编译出来的代码通常称为“字节码”。

这个运行时程序越复杂,它就可以在您的代码中没有包含的地方(即使是您使用的库中)进行更多的额外工作——例如,Java运行时环境(“JRE”)和Python运行时环境可以跟踪不再需要的内存分配,并告诉操作系统它可以安全地将该内存重新用于其他用途,并且它可以捕获您的代码尝试向操作系统发送非法请求的情况,并以可读的错误退出。

所有这些开销使它们比已编译的二进制语言更慢,但使得运行时强大而灵活; 在某些情况下,它甚至可以在启动后拉入其他代码,而无需重新开始。编译步骤意味着许多会导致程序崩溃的语句在代码运行之前被检测到;强大的运行时可以防止您的代码做傻事(


12
感谢您提供了不同语言的视角,这非常有启发性和教育意义。 - smwikipedia
5
好的回答。只需澄清一点:Python使用字节码 https://opensource.com/article/18/4/introduction-python-bytecode - Guzman Ojero
1
非常有信息量..谢谢你 - undefined
非常有信息量..谢谢 - Kaoutar
喜欢这个回答——这正是我在谷歌搜索问题时真正想要的!看到一个概念与其背景的互动是很有用的。 - undefined

37

在我看来,运行时就是它字面上的意思 - 程序运行时。你可以说某些东西发生在运行时或者编译时。

我认为运行时运行时库应该(如果它们不是)是两个不同的东西。“C运行时”对我来说不太合适。我称其为“C运行时库”。

回答你其他的问题:

我认为术语运行时可以扩展到包括程序运行时的环境和上下文,因此:

  • 它包含了任何在程序运行期间被称为“环境”的东西,例如其他进程,操作系统和使用的库的状态,其他进程的状态等。
  • 它在一般意义上不与您的代码交互,只是定义了您的代码在执行期间的工作环境,以及可用的资源。

这个答案在某种程度上仅仅是我的观点,不是事实或定义。


32

Matt Ball回答得很正确。我想通过示例来说明。

考虑运行在Turbo-Borland C/C++编译器(1991年的3.1版本)下编译的程序,并让它在32位的Windows(如Win 98/2000等)下运行。

这是一种16位编译器。你会发现你的所有程序都有16位指针。为什么当你的操作系统是32位时它还是这样?因为你的编译器已经设置了16位的执行环境,而32位的操作系统支持它。

通常所称的JRE(Java Runtime Environment)为Java程序提供了其可能需要的全部资源以执行。

实际上,运行时环境是虚拟机理念的产物。虚拟机实现了硬件和程序所需的原始接口。运行时环境采用这些接口,并将它们呈现给程序员使用。编译器开发人员需要这些功能来为其程序提供执行环境。


2
一个虚拟机实现了硬件和程序执行所需的“原始”接口。 -> 我不确定这个。 - Koray Tugay

10

运行时是您的代码开始运行并且您可以看到代码执行的许多重要细节的地方。

运行时负责分配内存、释放内存,使用操作系统的子系统(如文件服务、IO服务..网络服务等)

在您实际运行代码之前,您的代码将被称为“理论上的工作”,而运行时是帮助实现这一目标的好朋友。


4

运行时可以表示程序生命周期的当前阶段(运行时/编译时/加载时/链接时) 或者它可以指运行库,该库形成了基本的低级操作,与执行环境进行接口。 或者它可以表示运行时系统,这与执行环境相同。

在C程序的情况下,运行时是设置堆栈、堆等要求C环境所期望的代码。它实质上设置了语言承诺的环境。(在C的情况下,它可以有一个运行库组件,如crt0.lib之类)


4

运行时基本上指程序与计算机的硬件和操作系统交互的过程。 C语言没有自己的运行时,而是请求操作系统(基本上是内存的一部分)提供运行时来执行程序。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接