混合GC内存和 ptr

要特别注意的是,如果一个未被追踪的对象包含被追踪的对象,例如包含追踪的引用、字符串、序列。为了正确释放所有对象, 在释放未被追踪的内存之前,需要手动调用内置过程 reset :

  1. type
  2. Data = tuple[x, y: int, s: string]
  3. # 在堆上为 Data 分配内存:
  4. var d = cast[ptr Data](alloc0(sizeof(Data)))
  5. # 在垃圾回收(GC)堆上创建一个新的字符串:
  6. d.s = "abc"
  7. # 告知 GC 不再需要这个字符串:
  8. reset(d.s)
  9. # 释放内存:
  10. dealloc(d)

如果不调用 reset ,就绝不会释放分配给 d.s 字符串的内存。 这个例子对于程序底层来说,表现出两个重要的特性: sizeof 过程返回一个类型或值的字节大小。 cast 操作符可以避开类型系统: 编译器强制将 alloc0 (会返回一个未定义类型的指针)的结果认定为 ptr Data 类型。 只有在不可避免的情况下才应当进行转换,因为这会破坏类型安全,未知的 bug 可能导致崩溃。

注意: 当把垃圾收集的数据和非管理的内存混合使用时,需要了解这些低级细节。 这个例子之所以有效,是因为 alloc0 将内存初始化为零,而 alloc 不会 。 d.s 被初始化为二进制的零,因而可以处理字符串赋值。