这是 AGC,阿波罗导航计算机,用于阿波罗指令舱和登月舱。以几乎导致阿波罗 11 号着陆被擦洗而闻名。就在下降到月球表面的过程中,这台计算机因实时错误而崩溃。几次。产生系统错误 1201(执行溢出 - 没有空白区域)和系统错误 1202(执行溢出 - 没有核心集)。Armstrong 和 Aldrin 只看到了数字,您在照片右侧看到的 UI 设备太原始而无法显示字符串。是指导控制器史蒂夫贝尔斯知道这些数字的含义(他们在训练时从未见过错误)并且知道系统可以从中恢复。无论如何,通过给出 GO 拯救了着陆,他因此获得了总统自由勋章。
这可能是您的问题所要问的,尽管我们可以很确定您并没有试图让火箭着陆。“实时”这个词过去在软件工程中定义得很好,但被金融业弄糊涂了。在 Apollo 11 中,这意味着一个系统对外部事件的最大响应时间有一个非常严格的上限。火箭需要这样一个系统,有时候调整喷口也不能太晚,迟到会产生十亿美元的火球。金融业将其劫持为一个任意快的系统,有时迟到不会使机器蒸发,尽管它使交易损失的可能性更大。他们可能也认为这是一场灾难:)
您使用的内存分配器很重要,也没有在问题中定义。我任意假设您的程序在按需分页的虚拟内存操作系统上运行。不完全是实时系统的理想环境,但足够普遍,真正的实时操作系统表现不佳。
两阶段构造是一种用于处理初始化失败的技术,构造函数中抛出的异常很难处理,析构函数不会运行,因此如果在构造函数中分配而不使构造函数足够聪明,可能会导致资源泄漏来处理一个意外。另一种方法是稍后在成员函数内部进行,根据需要延迟分配。
所以你担心的是惰性分配会阻碍系统的响应能力。产生系统错误 1201。
这实际上不是 Linux 或 Windows 等按需分页虚拟内存操作系统的主要问题。这些操作系统上的内存分配器速度很快,它只分配虚拟内存。不需要任何费用,它是虚拟的。真正的成本出现在以后,当您真正开始使用分配的内存时。需求分页的“需求”发挥作用的地方。寻址数组元素将产生页面错误,迫使操作系统将寻址的虚拟内存页面映射到 RAM。这种页面错误相对便宜,称为“软”页面错误,如果机器没有处于压力之下并且必须取消映射另一个进程正在使用的页面来获取 RAM。你会期望操作系统能够抓取一个页面并映射它,
所以实际上,如果你做对了,并且在分配它时不尝试初始化整个数组,那么你的程序将受到数以万计的小针刺的开销。每一个都足够小,不会危及实时响应保证。不管你是提前分配内存还是延迟分配内存都会发生这种情况,所以是否使用两阶段构造无关紧要。
如果你想保证这也不会发生,或者想在初始化整个数组时对页面错误的风暴有弹性,那么你需要一种非常不同的方法,你需要页面锁定RAM 分配,以便操作系统无法取消映射页面。这总是需要修改操作系统设置,它通常不允许进程页面锁定大量内存。当然,两阶段建设也是不可能的。
请记住,程序很少知道如何处理分配失败。它们的行为几乎像异步异常一样,随时准备在程序的几乎任何部分中随时触发。尤其难以与实时要求相协调,因为内存不足而对实时事件没有响应的系统当然不比迟到的系统好。那仍然是一个火球;)因此,这本身就应该已经有足够的理由不打扰两阶段构造,只需在程序初始化时分配内存,然后再开始承诺实时响应。它使程序编码变得更加简单,失败的几率要低得多。
对于任何具有实时特性的软件来说,一个相当硬的要求是它不必与其他进程竞争来获取操作系统资源。预计整个机器只用于一个进程,您不再像 AGC 那样受限于 36864 字的绳索内存和 2048 字的 RAM。如今,硬件足够便宜且足够丰富,可以提供这样的保证。