| ... | @@ -445,8 +445,11 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -445,8 +445,11 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 445 | } | 445 | } |
| 446 | } | 446 | } |
| 447 | // free retained metadata for small allocations | 447 | // free retained metadata for small allocations |
| 448 | var empty_it = self.empty_buckets.inorderIterator(); | 448 | while (self.empty_buckets.getMin()) |node| { |
| 449 | while (empty_it.next()) |node| { | 449 | // remove the node from the tree before destroying it |
| | 450 | var entry = self.empty_buckets.getEntryForExisting(node); |
| | 451 | entry.set(null); |
| | 452 | |
| 450 | var bucket = node.key; | 453 | var bucket = node.key; |
| 451 | if (config.never_unmap) { | 454 | if (config.never_unmap) { |
| 452 | // free page that was intentionally leaked by never_unmap | 455 | // free page that was intentionally leaked by never_unmap |
| ... | @@ -1455,3 +1458,19 @@ test "bug 9995 fix, large allocs count requested size not backing size" { | ... | @@ -1455,3 +1458,19 @@ test "bug 9995 fix, large allocs count requested size not backing size" { |
| 1455 | buf = try allocator.realloc(buf, 2); | 1458 | buf = try allocator.realloc(buf, 2); |
| 1456 | try std.testing.expect(gpa.total_requested_bytes == 2); | 1459 | try std.testing.expect(gpa.total_requested_bytes == 2); |
| 1457 | } | 1460 | } |
| | 1461 | |
| | 1462 | test "retain metadata and never unmap" { |
| | 1463 | var gpa = std.heap.GeneralPurposeAllocator(.{ |
| | 1464 | .safety = true, |
| | 1465 | .never_unmap = true, |
| | 1466 | .retain_metadata = true, |
| | 1467 | }){}; |
| | 1468 | defer std.debug.assert(gpa.deinit() == .ok); |
| | 1469 | const allocator = gpa.allocator(); |
| | 1470 | |
| | 1471 | const alloc = try allocator.alloc(u8, 8); |
| | 1472 | allocator.free(alloc); |
| | 1473 | |
| | 1474 | const alloc2 = try allocator.alloc(u8, 8); |
| | 1475 | allocator.free(alloc2); |
| | 1476 | } |