1
0
mirror of https://github.com/golang/go synced 2024-11-23 20:00:04 -07:00

runtime: handle decommit failure gracefully on Windows

I have no test case for this at tip.
The original report included a program crashing at revision 88ac7297d2fa.
I tested this code at that revision and it does fix the crash.
However, at tip the reported code no longer crashes, presumably
because some allocation patterns have changed. I believe the
bug is still present at tip and that this code still fixes it.

Fixes #7143.

LGTM=alex.brainman
R=golang-codereviews, alex.brainman
CC=dvyukov, golang-codereviews
https://golang.org/cl/96300046
This commit is contained in:
Russ Cox 2014-05-13 01:09:38 -04:00
parent 2d1a9510ed
commit 30b8af98c0

View File

@ -36,10 +36,30 @@ void
runtime·SysUnused(void *v, uintptr n)
{
void *r;
uintptr small;
r = runtime·stdcall(runtime·VirtualFree, 3, v, n, (uintptr)MEM_DECOMMIT);
if(r == nil)
runtime·throw("runtime: failed to decommit pages");
if(r != nil)
return;
// Decommit failed. Usual reason is that we've merged memory from two different
// VirtualAlloc calls, and Windows will only let each VirtualFree handle pages from
// a single VirtualAlloc. It is okay to specify a subset of the pages from a single alloc,
// just not pages from multiple allocs. This is a rare case, arising only when we're
// trying to give memory back to the operating system, which happens on a time
// scale of minutes. It doesn't have to be terribly fast. Instead of extra bookkeeping
// on all our VirtualAlloc calls, try freeing successively smaller pieces until
// we manage to free something, and then repeat. This ends up being O(n log n)
// in the worst case, but that's fast enough.
while(n > 0) {
small = n;
while(small >= 4096 && runtime·stdcall(runtime·VirtualFree, 3, v, small, (uintptr)MEM_DECOMMIT) == nil)
small = (small / 2) & ~(4096-1);
if(small < 4096)
runtime·throw("runtime: failed to decommit pages");
v = (byte*)v + small;
n -= small;
}
}
void