8

请注意,这与 Microsoft 为宣传托管代码概念而大力宣传的 .NET CLR 无关。你们中的大多数人都知道托管代码已经存在了很长一段时间,并且与火箭科学并没有太大关系。

我想知道的是,为什么计算机发展过程中运行时安全的概念来得这么晚

我知道这就像在问“为什么第一辆福特 T 型车没有配备安全气囊和安全带?”。尽管如此,这个问题的相关性仍然存在,因为保护已知危险完全符合人性。例如,第一辆 T-Ford 的速度不足以激发安全气囊的研究。它的速度还不够快,以至于人们经常犯下致命的判断错误,以至于它会促使安全带成为许多国家的法律和标准。

在计算机进化中,它几乎是相反的。我们从组装机开始,这相当于用眼罩以 200 英里/小时的速度驾驶一辆 T-Ford。我有幸与这个时代的几位老卡车司机交谈,听到这些关于手工组装汇编代码、人工调试器、大量代码行等的故事。如果我们在 C 语言中犯了一个非常严重的错误,我们可能会结束蓝屏。几十年前,您最终可能会损坏硬件,天知道会发生什么。但这对我来说是个谜——这么多年了,我们所做的一切都是为了让崩溃不那么痛苦,只是蓝屏(很抱歉将 MS 用作任何东西的原型)。

防止已知危险不仅是人类的天性,而且任何程序员的天性都是自动化和系统化常用设施,如错误检查、内存诊断、日志框架、备份维护等。

为什么程序员/人类没有开始自动化确保他们提供给系统的代码不会损害系统的任务?是的,当然,性能。但是,嘿,这远远早于任何严重渗透的硬件标准。为什么主板没有设计有总线架构和额外的处理器来促进“托管代码”?

有没有什么比喻说 T 型福特汽车不够快以至于我错过了?

4

15 回答 15

18

内置于安全等的托管代码已经存在了很长时间。

原来的 PC 平台上没有它的空间,后来也没有加入。

自 70 年代以来,古老的 IBM 大型机就具有受保护的寻址、不可触碰的内核库、基于角色的安全性等。此外,所有汇编程序代码都由一个复杂的(当时)变更管理系统管理。(Univac、Burroughs 等也有类似的情况。)

Unix 从一开始就内置了相当不错的安全性(多年来并没有太大变化)。

所以我认为这在很大程度上是一个 Windows/Web 空间问题。

从未有过大型机病毒!世界上的大多数金融交易都在某个时候通过这些系统,因此它们似乎不是一个有吸引力的目标。

不过,IBM 内部邮件系统确实托管了第一个“木马”!

于 2009-04-28T09:25:22.917 回答
11

实际上,托管代码已经存在了很长时间。考虑:

  • LISP
  • 短暂聊天
  • BASIC(原味)

所有都提供了类似操作系统的环境,可以保护使用免受内存和其他资源控制问题的影响。所有这些都是相对的失败(只有在引入 PEEK 和 POKE 等允许您与底层系统混淆的功能时,BASIC 才真正成功)。

于 2009-04-28T09:24:54.070 回答
10

计算机还不够强大,要让它们足够强大太昂贵了。当您只能使用有限的资源时,每个字节和 CPU 周期都很重要。

我使用的第一台计算机是 1982 年的Sinclair ZX Spectrum。它的 RAM (16K) 比今天单个 Windows 字体文件的大小还小。那是相对最近的,在家用电脑时代。在 1970 年代中期之前,在家中拥有一台电脑的想法是不可想象的。

于 2009-04-28T09:12:03.867 回答
7

只是为了记录,我们从不手工编译程序集。我们手工组装了汇编语言代码。现在清楚了...

您的类比使问题变得模糊,因为在这个意义上,汽车的速度与计算机的速度不同:汽车速度的提高需要汽车安全性的改变,但驱动汽车的并不是计算机速度的提高需要改变计算机安全性,它是连接性的增加。换个角度看:对于汽车来说,提高速度是提高安全性的驾驶技术。对于计算机而言,提高速度是提高安全性的使能技术。

因此,第一辆汽车在事故中是安全的,因为它们很慢。第一台计算机是安全的,因为它们没有联网。

现在,通过安全带、安全气囊、ABS、防撞装置等,汽车变得更加安全。尽管您仍然无法拔下网络电缆,但通过其他技术使计算机变得安全。

这是一个简化,但我认为它是它的核心。那时我们不需要那些东西,因为计算机没有连接到网络。

于 2009-04-28T12:32:49.860 回答
6

让我们从第一原则考虑这一点。

托管平台提供了一个相对沙盒区域来运行从高级语言创建的程序代码,以更适合平台执行的形式(IL 字节码)。其中还有一些实用功能,例如垃圾收集和模块加载。

现在考虑一个本机应用程序 - 操作系统提供了一个相对沙盒区域(一个进程)来运行从高级语言创建的程序代码到更适合平台执行的形式(x86 操作码)。还有一些实用功能,如虚拟内存管理和模块加载。

没有太大区别,我认为我们首先管理平台的原因仅仅是因为它使平台编码更容易。它应该使代码在操作系统之间可移植,但 MS 并不关心这一点。安全性是托管平台的一部分,但应该是操作系统的一部分 - 例如。您的托管应用程序可以像正常过程一样写入文件和类似内容。限制这是一项安全功能,它不是本机上不存在的托管平台的一个方面。

最终,他们本可以将所有这些托管功能放入一组原生 dll 中,并放弃中间字节码的想法,转而将 JIT 编译为原生代码。像 GC 这样的“托管”特性很容易在本机堆上实现 - 请参阅 Boehm C++ 的示例。

我认为 MS 这样做的部分原因是它使编译器更容易编写,部分原因是 Java 就是这样产生的(而且 .NET 在很大程度上是 Java 的后代,如果只是在精神上的话),尽管 Java 这样做是为了交叉- 平台编码可能,MS 不关心的东西。

那么,为什么我们不从一开始就获得托管代码 - 因为您提到的所有作为“托管”代码的一部分的东西都是本机代码。我们今天拥有的托管平台只是在已经抽象的平台之上的额外抽象。高级语言添加了更多功能来保护您自己,缓冲区溢出已成为过去,但没有理由在 C 首次发明时不能在 C 中实现它们。只是他们不是。也许事后看来,这些功能似乎缺失了,但我敢肯定,在 10 年后,我们会问“为什么 C# 没有像我们今天那样实现明显有用的功能 XYZ”

于 2009-04-28T12:28:15.050 回答
4

300年前没有火车的原因是一样的。30年前没有手机的原因是一样的。同样的原因,我们仍然没有传送机。

技术随着时间的推移而发展,它被称为进化。

那时的计算机还不够强大。在后台运行垃圾收集器会杀死您的应用程序性能。

于 2009-04-28T09:38:55.317 回答
3

谈到为什么计算机没有托管代码级别的保护机制,而不是为什么 VM 不能在慢速硬件上运行的问题(已经在其他帖子中解释过)。简短的回答是确实如此。CPU 被设计为在发生错误代码时抛出异常,这样它就不会损坏系统。众所周知,Windows 处理这个问题的能力很差,但还有其他操作系统。Unix 将它作为信号传递,以便程序在不关闭系统的情况下终止。实际上,无论您是否正在运行托管代码,空指针异常都会以相同的方式导致 - 程序终止。虚拟内存确保程序不会与其他代码混淆,因此它们所能做的就是伤害自己。

这让我想到了第二点。如果您知道自己在做什么,所有这些都是不必要的。如果我想保持我的家具清洁,我根本不会把食物掉在上面。我不需要用塑料盖住我的房子,我只需要小心。如果你是一个草率的编码员,世界上最好的虚拟机不会拯救你,它只会让你运行你草率的代码而没有任何噪音。此外,如果您使用适当的封装,移植代码也很容易。当您是一名优秀的编码员时,托管代码并不能提供广泛的帮助。这就是为什么不是每个人都在使用它。这只是一个偏好问题,而不是更好/更糟。

就运行时安全而言,P 代码编译器无法预测机器代码无法预测,托管代码解释器也无法处理操作系统无法(或不能)处理的任何事情。带有额外总线、CPU 和指令集的主板要花更多的钱——IT 就是成本/性能比。

于 2009-04-28T14:17:18.300 回答
2

1970 年,内存成本约为 1 美元/位(没有通货膨胀)。你负担不起像这样的成本的豪华垃圾收集。

于 2009-04-28T09:22:53.920 回答
1

我认为像大多数问题一样,“为什么我们在 Y 年前的编程中没有 X”的答案是速度/资源分配。由于资源有限,他们需要尽可能有效地管理。与托管代码相关的通用类型的管理将过于耗费资源,以至于无法在当时的性能关键应用程序中受益。这也是为什么今天的性能关键代码仍然用 C、Fortran 或汇编程序编写的部分原因。

于 2009-04-28T14:55:26.133 回答
1

为什么我们不立刻造飞机和宇宙飞船,而不是到处乱搞马车之类的乏味的东西呢?

于 2009-04-28T14:58:40.697 回答
1

使用中间语言需要以下两件事之一:

  1. 运行时解释,这将有很大的性能损失(变化很大——有时是 2 倍或更少,但有时是 100 倍或更多)
  2. 即时编译器,它需要额外的 RAM,并且会增加与程序大小大致成比例的延迟,而不是执行的语句数量

多年来发生了变化的一件事是,许多程序运行其模式中使用最频繁的部分的次数比以前多得多。假设第一次执行任何特定语句将招致 1,000 倍于后续执行的惩罚。在每个语句平均运行 100 次的程序中,这种惩罚会产生什么影响?对于每条语句平均运行 1,000,000 次的程序,该惩罚会产生什么影响?

即时编译已经有很长一段时间了,但在 1980 年代或 1990 年代,性能成本将是不可接受的。随着技术的变化,JIT 编译的实际成本已经下降到完全实用的程度。

于 2011-03-29T17:39:07.323 回答
0

答案变得更清楚了——人类不是为编写程序而生的。机器应该这样做,让我们通过玩吃豆人来放松。

于 2009-04-28T11:02:02.137 回答
0

值得一提的是,我为我的计算语言课阅读了几篇论文(一篇由 CAR Hoare 撰写,另一篇由 Nicholas Wirth 撰写)在 60 年代和 70 年代尤其提倡这一点。

我无法确切说明为什么这些事情没有发生,但我的猜测是,这只是事后看来显而易见的事情之一,当时并不明显。并不是早期的编译器不关心安全性。这是因为他们对如何做到这一点有不同的想法。

Hoare 提到了“结帐编译器”的想法。据我所知,这本质上是一个进行静态分析的编译器。对他来说,这是一种失败的流行技术(或者至少没有解决它想要解决的那么多问题)。他的解决方案是通过创建托管代码来使编程语言更加安全(或者至少他用现代术语是这样说的)。

我想一旦 C(以及后来的 C++)流行起来,托管代码的想法基本上就死了。并不是说 C 是一种糟糕的语言,只是它旨在成为一种汇编语言而不是一种应用程序编程语言。

如果有机会,您可能会阅读关于编程语言设计的提示。如果你对这类事情感兴趣,这是一本很好的读物。

于 2009-04-28T12:41:40.650 回答
0

这个问题的最佳答案是,恕我直言,当时没有人知道托管代码。知识实际上是随着时间的推移而发展的。与建筑或农业等领域相比,计算机科学是一个非常年轻的领域。因此,关于该领域的集体知识也很年轻,并且会随着时间的推移而发展。也许几年后我们会遇到一些新现象,有人会问同样的问题,“为什么以前没有人想到 XYZ?”。

于 2009-04-28T12:59:29.110 回答
-1

我想说这主要是由于对更改的阻力以及对垃圾收集效率低下的错误看法,延迟了 GC 和相关技术的采用。当然,英特尔 8086 上的脑死亡分段内存模型并不能完全帮助促进 PC 上的健全内存管理。

于 2009-04-28T09:39:06.940 回答