将GC内存和 ptr 混用
如果未追踪对象包含追踪对象(如追踪引用,字符串或序列),则需要特别小心:为了正确释放所有内容,必须在手动释放未追踪内存之前调用内置过程 GCunref :
- type
- Data = tuple[x, y: int, s: string]
- # 为堆上的Data分配内存:
- var d = cast[ptr Data](alloc0(sizeof(Data)))
- # 在垃圾收集堆上创建一个新字符串:
- d.s = "abc"
- # 告诉GC不再需要该字符串:
- GCunref(d.s)
- # 释放内存:
- dealloc(d)
没有 GCunref 调用,为 d.s 字符串分配的内存永远不会被释放。 该示例还演示了低级编程的两个重要特性: sizeof proc以字节为单位返回类型或值的大小。 cast 运算符可以绕过类型系统:编译器被强制处理 alloc0 调用的结果(返回一个无类型的指针),就好像它是 ptr Data 类型。 只有在不可避免的情况下才能进行强转:它会破坏类型安全性并且错误可能导致隐蔽的崩溃。
注意: 该示例仅起作用,因为内存初始化为零( alloc0 而不是 alloc 执行此操作): d.s 因此初始化为二进制零,字符串赋值可以处理。 在将垃圾收集数据与非托管内存混合时,需要知道这样的低级细节。