-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Reduce address space waste of std.heap.page_allocator on Windows #17413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
According to https://stackoverflow.com/questions/20023446/is-virtualalloc-alignment-consistent-with-size-of-allocation for context "64KB is the value of SYSTEM_INFO.dwAllocationGranularity". 4 KB is the page size and allocations are only aligned to full page sizes. It looks like Windows uses memory overcommit only for stack sizes and not for heap allocations, see https://superuser.com/questions/1194263/will-microsoft-windows-10-overcommit-memory.
Memory is only commited, if the page is accessed, not before. See also https://stackoverflow.com/questions/20023446/is-virtualalloc-alignment-consistent-with-size-of-allocation.
This does not specify how this is a problem for your use case. Allocators are expected to do batching for performance. Can you justify, why you need control over the default amount of reserved pages? |
It is generally assumed that |
No, I was playing around with
I like this idea |
@mikastiv why was this closed? |
I didn't get the feeling that it needed to be addressed by the answers I got and there hasn't been any posts since last week |
I think it's worth keeping open if you don't mind. When combined with #17377, it is behavior that will end up mattering since the GeneralPurposeAllocator intentionally tries to avoid re-using virtual addresses and this caveat will make Windows exhaust the virtual address space more quickly. |
Isn't this going to blow out the TLB. It is very serious issue with some processes with a large working set, especially when huge pages aren't in use. |
AFAIK it's primarily a strategy intended for catching double frees. When #12484 is addressed, it almost certainly won't be part of the release-mode GeneralPurposeAllocator. |
to get ~4MB virtual memory usage I'll investigate more.
This is the trace of the C program (<0.5MB virtual memory usage): Most likely the process or job limit https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_extended_limit_information or https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_basic_limit_information is too low. UPDATE This issue is unrelated due to incorrect usage, abi problem or another problem on my side. The Windows behavior is however still very interesting and makes me question the robustness of the implementation. |
related issue I am getting weird print statment from this allocator on a caught error that I belive is the page space
the code is const std = @import("std");
const Node = struct {
next: ?*Node,
data: [1048576 - @sizeOf(?*Node)]u8,
};
comptime {
std.debug.assert(@sizeOf(Node) == 1048576);
}
pub fn main() !void {
const allocator = std.heap.page_allocator;
var head: ?*Node = null;
var current: ?*Node = null;
var nodeCount: usize = 0;
var leaker: ?*u8 = null; //we have to leak since pointers are more than a byte
std.debug.print("Allocating memory until a crash...\n", .{});
while (true) {
const newNode = allocator.create(Node) catch { //|err| {
//std.debug.print("Failed to create node, system possibly OOM. Error: {}\n", .{ err });
while (true) {
leaker = allocator.create(u8) catch {
break;
};
}
break;
};
newNode.next = null; // Set next pointer to null after allocation
if (head == null) {
head = newNode;
} else {
current.?.next = newNode;
}
current = newNode;
nodeCount += 1;
std.debug.print("\rTotal memory allocated: {d} megabytes ", .{nodeCount});
}
// Cleanup, freeing all nodes
while (head) |node| {
const next = node.next;
allocator.destroy(node);
head = next;
}
std.debug.print("Memory has been released.\n", .{});
}
|
Original writeup no longer applies but there are still related issue to fix such as
Seems to happen in low memory conditions. I believe other than that, remaining issues are covered by: |
Currently, the
PageAllocator
does allocations aligned withstd.mem.page_size
(4KB on Windows) using VirtualAlloc. Windows requires it's allocations to be aligned on 64KB boundaries, so everytime this allocator is used, up to 60KB of address space is wasted.I made a small program to illustrate. All the addresses are 64KB apart (except the first one):
Outputs:
A simple solution would be to use Windows' allocation granularity instead of the page size, although this would commit at least 64KB every allocations instead of 4KB.
The text was updated successfully, but these errors were encountered: