我在 Zig(使用 v0.13.0)的内存管理方面遇到了麻烦,涉及全局和静态局部变量的去初始化。
我编写了以下程序,但内存泄漏,因此在为GeneralPurposeAllocator启用安全性时程序会出现混乱。我已阅读文档,尤其是有关静态局部变量的部分,但它没有提及(或者它在另一个部分,我错过了)有关如何取消初始化内存的任何内容。
const std = @import("std");
const key_t = u32;
const value_t = u128;
const computed_map_t = std.AutoHashMap(key_t, value_t);
var default_gpa: std.heap.GeneralPurposeAllocator(.{}) = undefined;
const default_allocator = default_gpa.allocator();
pub fn fibonacci(value: key_t) value_t {
const _state = struct {
// How do I deinit this map on program end ?
// Or is it possible to mark it as "ok to leak" ?
var previously_computed = computed_map_t.init(default_allocator);
};
if (value == 0) return 0;
if (value == 1 or value == 2) return 1;
// Fallback "dumb" implementation because HashMap cannot be used in comptime
if (@inComptime()) {
return fibonacci(value - 2) + fibonacci(value - 1);
} else {
if (_state.previously_computed.get(value)) |res| {
return res;
} else {
const res = fibonacci(value - 2) + fibonacci(value - 1);
_state.previously_computed.put(value, res) catch {
@panic("Something went wrong");
};
return res;
}
}
}
pub fn main() !void {
default_gpa = @TypeOf(default_gpa){};
defer {
if (.leak == default_gpa.deinit()) {
@panic("GPA leaked !");
}
}
const value = 5;
const result = fibonacci(value);
std.debug.print("fibonacci({d}) = {d}\n", .{ value, result });
}
我曾考虑过在主函数中初始化映射并将其fibonacci
作为指针传递给该函数,但是这有点违背了要点(这个映射只在函数中有用,所以我想将这个变量的范围限制在函数范围内)。
我是不是漏掉了什么?或者,你有什么“窍门”能让你以干净的方式实现这一点吗?
根据您设置的方式,它将始终显示为泄漏,因为由于您已隐藏它,因此无法获取引用来取消初始化地图。
我认为更好的选择是初始化映射并从函数访问它,而不是拉取对 default_allocator 的引用。
一般来说,如果你试图以这种方式隐藏分配,zig 会让你的生活变得困难。lang 哲学的核心部分就是防止这种幽灵分配风格。
我个人会选择拥有映射的结构,并具有执行映射查找的函数,否则,如果没有匹配项,则委托给完整的 impl 函数。这样,它也会变成你可以通用的东西。
您会注意到这个 init/deinit 组合在 std 中使用非常广泛,而且我想象随着 zig 本机库的出现,它们也会将其用于通用 API。