将GC内存和 ptr 混用

如果未追踪对象包含追踪对象(如追踪引用,字符串或序列),则需要特别小心:为了正确释放所有内容,必须在手动释放未追踪内存之前调用内置过程 GCunref

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

没有 GCunref 调用,为 d.s 字符串分配的内存永远不会被释放。 该示例还演示了低级编程的两个重要特性: sizeof proc以字节为单位返回类型或值的大小。 cast 运算符可以绕过类型系统:编译器被强制处理 alloc0 调用的结果(返回一个无类型的指针),就好像它是 ptr Data 类型。 只有在不可避免的情况下才能进行强转:它会破坏类型安全性并且错误可能导致隐蔽的崩溃。

注意: 该示例仅起作用,因为内存初始化为零( alloc0 而不是 alloc 执行此操作): d.s 因此初始化为二进制零,字符串赋值可以处理。 在将垃圾收集数据与非托管内存混合时,需要知道这样的低级细节。