我知道 GC 在 Ada 开发的时候并不流行,对于嵌入式编程的主要用例来说,它仍然不是一个好的选择。
但是考虑到 Ada 是一种通用编程语言,为什么在该语言的后续版本和编译器实现中没有引入部分和可选的(仅跟踪显式标记的内存对象)垃圾收集器。
我简直无法再想开发一个没有垃圾收集器的普通桌面应用程序了。
我知道 GC 在 Ada 开发的时候并不流行,对于嵌入式编程的主要用例来说,它仍然不是一个好的选择。
但是考虑到 Ada 是一种通用编程语言,为什么在该语言的后续版本和编译器实现中没有引入部分和可选的(仅跟踪显式标记的内存对象)垃圾收集器。
我简直无法再想开发一个没有垃圾收集器的普通桌面应用程序了。
Ada 的设计考虑了军事应用。其设计中的一大优先事项是确定性。即,希望 Ada 程序每次在任何环境下、在所有操作系统下都能始终如一地执行完全相同的方式……就是这样。
垃圾收集器将一个应用程序变成两个应用程序,相互对抗。当 GC 决定开始工作时,Java 程序会以随机间隔出现打嗝,如果它太慢,则应用程序有时可能会用完堆而不是其他应用程序。
简化:垃圾收集器在程序中引入了设计者不想要的一些可变性。你弄得一团糟——你把它清理干净!每次相同的代码,相同的行为。
请注意,并不是说艾达在全球取得了巨大的成功。
因为 Ada 是为实时控制武器的防御系统而设计的,而垃圾收集会干扰您的应用程序的时间。这是危险的,这就是为什么多年来,Java 一直警告它不能用于医疗保健和军事控制系统。
我认为 Java 不再有这样的免责声明的原因是因为底层硬件变得更快,以及 Java 具有更好的 GC 算法和更好地控制 GC 的事实。
请记住,Ada 是在 1970 年代和 1980 年代开发的,当时计算机的功能远没有今天强大,在控制应用程序中,时间问题是最重要的。
答案更复杂:由于实时限制等,Ada 不需要垃圾收集器。但是,该语言经过巧妙设计,允许实现垃圾收集器。
虽然,许多(几乎所有)编译器不包含垃圾收集器,但有一些值得注意的实现:
网络上还有很多关于 Ada 垃圾收集的其他资源。这个话题已经被详细讨论过了,主要是因为在 90 年代中期与 Java 的激烈竞争(看看这个页面:)"Ada 95 is what the Java language should have been"
,在微软绘制 C# 之前,Java 是“下一件大事”。
首先,该语言中没有真正禁止垃圾收集的内容。
其次,一些实现确实执行垃圾收集。特别是针对 JVM 垃圾收集的所有实现。
第三,有一种方法可以让所有编译器都进行一些垃圾收集。您会看到,当访问类型超出范围时,如果您特别告诉语言留出一定数量的空间来存储其对象,那么该空间将在那时被销毁。我过去用它来收集一些垃圾。您使用的声明巫毒是:
type Foo is access Blah;
for Foo'storage_size use 100_000_000; --// 100K
如果这样做,那么当 Foo 类型超出范围时,分配给由 Foo 指针指向的 Blah 对象的所有(100K)内存将被清除。由于 Ada 允许您将子例程嵌套在其他子例程中,因此它特别强大。
要了解有关 storage_size 和存储池可以为您做什么的更多信息,请参阅LRM 13.11
第四,编写良好的 Ada 程序不像 C 程序那样倾向于依赖动态内存分配。C 有许多设计漏洞,实践者学会了使用指针来绘制。很多这些成语在 Ada 中并不重要。
首先,我想知道这些天谁在使用 Ada。我实际上很喜欢这种语言,甚至还有一个用于 Linux/Ada 的 GUI 库,但多年来我没有听说过任何关于 Ada 积极开发的消息。由于它的军事联系,我真的不确定它是否是古老的历史或如此巨大的成功以至于所有提及它的使用都是机密的。
我认为 Ada 没有 GC 有几个原因。首先,最重要的是,它可以追溯到大多数编译语言主要使用堆栈或静态内存的时代,或者在少数情况下,显式堆分配/释放。GC 作为一种通用哲学实际上直到 1990 年左右才开始流行,当时 OOP、改进的内存管理算法和强大到足以节省运行它的周期的处理器都进入了它们自己的领域。1989 年,简单地编译 Ada 对 IBM 4331 大型机的影响简直是无情的。现在我有一部手机可以胜过那台机器的 CPU。
另一个很好的理由是有些人认为严格的程序设计包括对内存资源的精确控制,并且不应该容忍让动态获取的对象浮动。可悲的是,随着动态内存越来越成为规则,太多的人最终泄漏了内存。另外,就像汇编语言相对于高级语言的“效率”,以及原始 JDBC 相对于 ORM 系统的“效率”一样,手动内存管理的“效率”随着规模的扩大而趋于倒置(我看过 ORM 基准测试)其中 JDBC 等价物的效率只有一半)。我知道这违反直觉,但如今系统在全局优化大型应用程序方面要好得多,而且它们能够针对表面上的微小变化进行彻底的重新优化。
恐怕我将不得不与那些说实时系统负担不起 GC 内存的人不同。GC 不再是每隔几分钟就会冻结整个系统的东西。如今,我们有更智能的方法来回收记忆。
你的问题不正确。确实如此。请参阅为您处理 GC 的包 ada.finalization。
我想我会分享一个非常简单的例子来说明如何实现一个 Free() 过程(它将以所有 C 程序员都熟悉的方式使用)......
with Ada.Integer_Text_IO, Ada.Unchecked_Deallocation;
use Ada.Integer_Text_IO;
procedure Leak is
type Int_Ptr is access Integer;
procedure Free is new Ada.Unchecked_Deallocation (Integer, Int_Ptr);
Ptr : Int_Ptr := null;
begin
Ptr := new Integer'(123);
Free (Ptr);
end Leak;
在程序结束时调用 Free 会将分配的整数返回到存储池(C 语言中的“堆”)。您可以使用 valgrind 来证明这确实可以防止 4 个字节的内存泄漏。
The Ada.Unchecked_Deallocation (a generically defined procedure) can be used on (I think) any type that may be allocated using the "new" keyword. The Ada Reference Manual ("13.11.2 Unchecked Storage Deallocation") has more details.