-
Notifications
You must be signed in to change notification settings - Fork 44
win: release physical pages in vmDeallocatePhysicalPages + hintMemoryNotNeededSoon #226
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| /* | ||
| * Copyright (C) 2025 Apple Inc. All rights reserved. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * 1. Redistributions of source code must retain the above copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in the | ||
| * documentation and/or other materials provided with the distribution. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | ||
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | ||
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | ||
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | ||
| * THE POSSIBILITY OF SUCH DAMAGE. | ||
| */ | ||
|
|
||
| #include "config.h" | ||
| #include "WindowsVMDecommitTest.h" | ||
|
|
||
| #include <stdio.h> | ||
| #include <wtf/Assertions.h> | ||
|
|
||
| #if OS(WINDOWS) | ||
| #include <windows.h> | ||
| #include <psapi.h> | ||
| #include <wtf/OSAllocator.h> | ||
| #endif | ||
|
|
||
| WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN | ||
|
|
||
| #if OS(WINDOWS) | ||
| static SIZE_T workingSetSize() | ||
| { | ||
| PROCESS_MEMORY_COUNTERS counters; | ||
| counters.cb = sizeof(counters); | ||
| if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) | ||
| return 0; | ||
| return counters.WorkingSetSize; | ||
| } | ||
| #endif | ||
|
|
||
| void testWindowsVMDecommit() | ||
| { | ||
| #if OS(WINDOWS) | ||
| printf("Testing Windows OSAllocator::hintMemoryNotNeededSoon releases pages (bun#30562)\n"); | ||
|
|
||
| // 64 MiB is large enough to be unambiguous against background working-set | ||
| // noise (a few MiB of jitter between snapshots is normal) yet small enough | ||
| // to fit comfortably on any CI machine. | ||
| const size_t regionSize = 64 * 1024 * 1024; | ||
|
|
||
| // Reserve + commit a single region so we know the exact page range and so | ||
| // VirtualQuery in the fallback path walks over reservations we control. | ||
| void* region = VirtualAlloc(nullptr, regionSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | ||
| RELEASE_ASSERT(region); | ||
|
|
||
| // Touch every page to bring them into the working set. Without this, | ||
| // Windows lazy-commits — the pages won't show up in WorkingSetSize and | ||
| // there'd be nothing to observe being released. | ||
| SYSTEM_INFO systemInfo; | ||
| GetSystemInfo(&systemInfo); | ||
| const size_t pageSize = systemInfo.dwPageSize; | ||
| volatile unsigned char* bytes = static_cast<unsigned char*>(region); | ||
| for (size_t offset = 0; offset < regionSize; offset += pageSize) | ||
| bytes[offset] = static_cast<unsigned char>(offset & 0xff); | ||
|
|
||
| const SIZE_T before = workingSetSize(); | ||
|
|
||
| // The call under test. Before the fix this was an empty stub — the | ||
| // working set would not change. After the fix it calls DiscardVirtualMemory | ||
| // (or the MEM_RESET + VirtualUnlock fallback) which evicts the pages. | ||
| WTF::OSAllocator::hintMemoryNotNeededSoon(region, regionSize); | ||
|
|
||
| const SIZE_T after = workingSetSize(); | ||
|
|
||
| VirtualFree(region, 0, MEM_RELEASE); | ||
|
|
||
| printf(" working set before: %zu bytes\n", static_cast<size_t>(before)); | ||
| printf(" working set after : %zu bytes\n", static_cast<size_t>(after)); | ||
|
|
||
| // Allow for the OS to keep a small residue in the working set. We require | ||
| // at least half the region to have been evicted — the previous empty-stub | ||
| // implementation would produce ~0 bytes of drop. | ||
| const SIZE_T minDrop = regionSize / 2; | ||
| if (before < after || before - after < minDrop) { | ||
| fprintf(stderr, "FAIL: hintMemoryNotNeededSoon did not release pages — " | ||
| "working set drop was %zu bytes, expected at least %zu bytes.\n", | ||
| before > after ? static_cast<size_t>(before - after) : static_cast<size_t>(0), | ||
| static_cast<size_t>(minDrop)); | ||
| RELEASE_ASSERT_NOT_REACHED(); | ||
| } | ||
| printf("PASS: hintMemoryNotNeededSoon released %zu bytes from the working set\n", | ||
| static_cast<size_t>(before - after)); | ||
| #else | ||
| printf("testWindowsVMDecommit: skipped (not Windows)\n"); | ||
| #endif | ||
| } | ||
|
|
||
| WTF_ALLOW_UNSAFE_BUFFER_USAGE_END | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| /* | ||
| * Copyright (C) 2025 Apple Inc. All rights reserved. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * 1. Redistributions of source code must retain the above copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in the | ||
| * documentation and/or other materials provided with the distribution. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | ||
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | ||
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | ||
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | ||
| * THE POSSIBILITY OF SUCH DAMAGE. | ||
| */ | ||
|
|
||
| #pragma once | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /* Regression test for bun#30562: Windows vmDeallocatePhysicalPages and | ||
| * OSAllocator::hintMemoryNotNeededSoon must release physical pages, not | ||
| * just MEM_RESET. */ | ||
| void testWindowsVMDecommit(void); | ||
|
|
||
| #ifdef __cplusplus | ||
| } /* extern "C" */ | ||
| #endif |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -26,6 +26,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "config.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <wtf/OSAllocator.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <algorithm> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <windows.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <wtf/Assertions.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <wtf/DataLog.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -127,8 +128,41 @@ void OSAllocator::releaseDecommitted(void* address, size_t bytes, unsigned) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CRASH(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void OSAllocator::hintMemoryNotNeededSoon(void*, size_t) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void OSAllocator::hintMemoryNotNeededSoon(void* address, size_t bytes) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Windows equivalent of madvise(MADV_DONTNEED). The pages must remain | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // accessible (the POSIX version leaves the mapping in place and just | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // drops the physical backing), so we can't MEM_DECOMMIT here. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Previously this was an empty stub, which meant scavenger hints were | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // silently dropped on Windows — long-running processes accumulated | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // hundreds of MB of committed-but-zero pages that the OS never | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // reclaimed (bun#30562). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // DiscardVirtualMemory releases the physical frames immediately and | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // removes the pages from the working set while keeping the virtual | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // mapping committed. On older Windows 10 builds and on ranges spanning | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // multiple reservations it can fail, so we fall back to a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // per-reservation MEM_RESET loop + VirtualUnlock, which has the same | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // effect with lazy reclaim. This mirrors the pattern already used in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // libpas (pas_page_malloc.c). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!bytes) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (DiscardVirtualMemory(address, bytes)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size_t totalSeen = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void* currentPtr = address; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while (totalSeen < bytes) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MEMORY_BASIC_INFORMATION memInfo; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SIZE_T queried = VirtualQuery(currentPtr, &memInfo, sizeof(memInfo)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!queried || !memInfo.RegionSize) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size_t chunkSize = std::min<size_t>(memInfo.RegionSize, bytes - totalSeen); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| VirtualAlloc(currentPtr, chunkSize, MEM_RESET, PAGE_READWRITE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currentPtr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(currentPtr) + memInfo.RegionSize); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| totalSeen += memInfo.RegionSize; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| VirtualUnlock(address, bytes); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+151
to
166
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fallback branch is inverted in Line 151 currently runs the MEM_RESET/VirtualUnlock path only when Suggested fix- if (DiscardVirtualMemory(address, bytes)) {
+ if (!DiscardVirtualMemory(address, bytes)) {
size_t totalSeen = 0;
void* currentPtr = address;
while (totalSeen < bytes) {
MEMORY_BASIC_INFORMATION memInfo;
SIZE_T queried = VirtualQuery(currentPtr, &memInfo, sizeof(memInfo));
if (!queried || !memInfo.RegionSize)
return;
size_t chunkSize = std::min<size_t>(memInfo.RegionSize, bytes - totalSeen);
VirtualAlloc(currentPtr, chunkSize, MEM_RESET, PAGE_READWRITE);
currentPtr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(currentPtr) + memInfo.RegionSize);
totalSeen += memInfo.RegionSize;
}
VirtualUnlock(address, bytes);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool OSAllocator::tryProtect(void* address, size_t bytes, bool readable, bool writable) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -429,10 +429,41 @@ inline void vmZeroAndPurge(void* p, size_t vmSize, VMTag usage) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inline void vmDeallocatePhysicalPages(void* p, size_t vmSize) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Windows equivalent of madvise(MADV_DONTNEED): release physical backing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // while keeping the virtual range committed and accessible. The paired | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // vmAllocatePhysicalPages() re-commits on reuse. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // MEM_RESET alone is NOT sufficient — it marks contents as uninteresting | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // but does not release physical frames or remove pages from the working | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // set, so RSS and commit charge grow unboundedly on long-running | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // processes (bun#30562). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // DiscardVirtualMemory frees the physical pages immediately and removes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // them from the working set. On older Windows 10 builds and on ranges | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // spanning multiple reservations it can fail, so we fall back to a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // per-reservation MEM_RESET loop + VirtualUnlock, which evicts the pages | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // from the working set with lazy reclaim. This mirrors the pattern | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // already used in libpas (pas_page_malloc.c). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vmValidatePhysical(p, vmSize); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool writable = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool executable = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| VirtualAlloc(p, vmSize, MEM_RESET, protection(writable, executable)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (DiscardVirtualMemory(p, vmSize)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool writable = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool executable = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size_t totalSeen = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void* currentPtr = p; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while (totalSeen < vmSize) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MEMORY_BASIC_INFORMATION memInfo; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SIZE_T bytes = VirtualQuery(currentPtr, &memInfo, sizeof(memInfo)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RELEASE_BASSERT(bytes == sizeof(memInfo)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RELEASE_BASSERT(memInfo.RegionSize > 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size_t chunkSize = std::min<size_t>(memInfo.RegionSize, vmSize - totalSeen); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| VirtualAlloc(currentPtr, chunkSize, MEM_RESET, protection(writable, executable)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currentPtr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(currentPtr) + memInfo.RegionSize); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| totalSeen += memInfo.RegionSize; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // VirtualUnlock of unlocked pages evicts them from the working set, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // which MEM_RESET alone does not do. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| VirtualUnlock(p, vmSize); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+459
to
+465
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're discarding the return value for both |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+448
to
+466
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Line 448 gates the MEM_RESET + Suggested fix- if (DiscardVirtualMemory(p, vmSize)) {
+ if (!DiscardVirtualMemory(p, vmSize)) {
bool writable = true;
bool executable = true;
size_t totalSeen = 0;
void* currentPtr = p;
while (totalSeen < vmSize) {
MEMORY_BASIC_INFORMATION memInfo;
SIZE_T bytes = VirtualQuery(currentPtr, &memInfo, sizeof(memInfo));
RELEASE_BASSERT(bytes == sizeof(memInfo));
RELEASE_BASSERT(memInfo.RegionSize > 0);
size_t chunkSize = std::min<size_t>(memInfo.RegionSize, vmSize - totalSeen);
VirtualAlloc(currentPtr, chunkSize, MEM_RESET, protection(writable, executable));
currentPtr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(currentPtr) + memInfo.RegionSize);
totalSeen += memInfo.RegionSize;
}
// VirtualUnlock of unlocked pages evicts them from the working set,
// which MEM_RESET alone does not do.
VirtualUnlock(p, vmSize);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inline void vmAllocatePhysicalPages(void* p, size_t vmSize) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Post-hint measurement is timing-sensitive and can flake
Line 83 takes only one immediate snapshot after the hint. For lazy reclaim paths, eviction may lag briefly, causing intermittent false failures.
Suggested fix
🤖 Prompt for AI Agents