Deleak the leaks

There is a chance that leaks from VkAllocator result from leaky allocations while deinitializing.
This commit is contained in:
2025-11-28 00:31:54 +01:00
parent 9d60be86ab
commit d1f6679f42

View File

@@ -4,8 +4,9 @@ const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
allocations: std.AutoHashMapUnmanaged(?*anyopaque, usize) = .empty, allocations: std.AutoHashMapUnmanaged(*anyopaque, usize) = .empty,
mutex: std.Thread.Mutex = .{}, mutex: std.Thread.Mutex = .{},
allocated_bytes: usize = 0,
interface: vk.AllocationCallbacks, interface: vk.AllocationCallbacks,
@@ -15,6 +16,8 @@ interface: vk.AllocationCallbacks,
// with the same, relatively big alignment and hope for the best. // with the same, relatively big alignment and hope for the best.
const actual_alignment: std.mem.Alignment = .@"16"; const actual_alignment: std.mem.Alignment = .@"16";
const log = std.log.scoped(.vk_allocator);
pub fn init(allocator: std.mem.Allocator) !*VkAllocator { pub fn init(allocator: std.mem.Allocator) !*VkAllocator {
// NOTE We allocate the structure to pin its address. // NOTE We allocate the structure to pin its address.
const self = try allocator.create(VkAllocator); const self = try allocator.create(VkAllocator);
@@ -33,6 +36,19 @@ pub fn init(allocator: std.mem.Allocator) !*VkAllocator {
pub fn deinit(self: *VkAllocator) void { pub fn deinit(self: *VkAllocator) void {
std.log.debug("Deinitializing {*}", .{self}); std.log.debug("Deinitializing {*}", .{self});
if (self.allocated_bytes > 0) {
log.warn("{d} byte(s) still allocated while deinitializing", .{self.allocated_bytes});
}
if (self.allocations.size > 0) {
log.warn("{d} allocation(s) still tracked while deinitializing", .{self.allocations.size});
var it = self.allocations.iterator();
var index: usize = 0;
while (it.next()) |entry| : (index += 1) {
log.warn("Leaked allocation ({d}/{d}) at 0x{x} of {d} byte(s)", .{ index + 1, self.allocations.size, @intFromPtr(entry.key_ptr.*), entry.value_ptr.* });
const memory = @as([*]align(actual_alignment.toByteUnits()) u8, @ptrCast(@alignCast(entry.key_ptr.*)))[0..entry.value_ptr.*];
self.allocator.free(memory);
}
}
const allocator = self.allocator; const allocator = self.allocator;
@@ -60,6 +76,8 @@ fn allocationFunction(
const memory = self.allocator.alignedAlloc(u8, actual_alignment, size) catch return null; const memory = self.allocator.alignedAlloc(u8, actual_alignment, size) catch return null;
self.allocations.putAssumeCapacity(memory.ptr, size); self.allocations.putAssumeCapacity(memory.ptr, size);
self.allocated_bytes += size;
//log.debug("Allocated {d} bytes(s) at 0x{x}", .{ size, @intFromPtr(memory.ptr) });
return memory.ptr; return memory.ptr;
} }
@@ -94,11 +112,13 @@ fn reallocationFunction(
std.debug.assert(std.mem.isAligned(@intFromPtr(memory.ptr), alignment)); std.debug.assert(std.mem.isAligned(@intFromPtr(memory.ptr), alignment));
if (maybe_p_original) |p_original| { if (maybe_p_original) |p_original| {
const removed = self.allocations.remove(p_original); const old_size = self.allocations.fetchRemove(p_original).?.value;
std.debug.assert(removed); self.allocated_bytes -= old_size;
} }
self.allocations.putAssumeCapacityNoClobber(memory.ptr, size); self.allocations.putAssumeCapacityNoClobber(memory.ptr, size);
self.allocated_bytes += size;
//log.debug("Reallocated into {d} bytes(s) at 0x{x} from 0x{x}", .{ size, @intFromPtr(memory.ptr), @intFromPtr(maybe_p_original) });
return memory.ptr; return memory.ptr;
} }
@@ -114,6 +134,7 @@ fn freeFunction(
defer self.mutex.unlock(); defer self.mutex.unlock();
const size = self.allocations.fetchRemove(p_memory).?.value; const size = self.allocations.fetchRemove(p_memory).?.value;
self.allocated_bytes -= size;
const memory = @as([*]align(actual_alignment.toByteUnits()) u8, @ptrCast(@alignCast(p_memory)))[0..size]; const memory = @as([*]align(actual_alignment.toByteUnits()) u8, @ptrCast(@alignCast(p_memory)))[0..size];
self.allocator.free(memory); self.allocator.free(memory);