summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/system/alloc.nim24
-rw-r--r--tests/system/tdeepcopy.nim1
-rw-r--r--tests/system/trealloc.nim21
3 files changed, 43 insertions, 3 deletions
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index 3a8e8a1b6..5b0955132 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -100,7 +100,8 @@ type
     freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
     chunkStarts: IntSet
     root, deleted, last, freeAvlNodes: PAvlNode
-    locked: bool # if locked, we cannot free pages.
+    locked, blockChunkSizeIncrease: bool # if locked, we cannot free pages.
+    nextChunkSize: int
 {.deprecated: [TLLChunk: LLChunk, TAvlNode: AvlNode, TMemRegion: MemRegion].}
 
 # shared:
@@ -275,9 +276,25 @@ proc pageAddr(p: pointer): PChunk {.inline.} =
   #sysAssert(Contains(allocator.chunkStarts, pageIndex(result)))
 
 proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
+  if not a.blockChunkSizeIncrease:
+    a.nextChunkSize =
+      if a.currMem < 64 * 1024: PageSize*4
+      else: a.nextChunkSize*2
+  var size = size
+
+  if size > a.nextChunkSize:
+    result = cast[PBigChunk](osAllocPages(size))
+  else:
+    result = cast[PBigChunk](osTryAllocPages(a.nextChunkSize))
+    if result == nil:
+      result = cast[PBigChunk](osAllocPages(size))
+      a.blockChunkSizeIncrease = true
+    else:
+      size = a.nextChunkSize
+
   incCurrMem(a, size)
   inc(a.freeMem, size)
-  result = cast[PBigChunk](osAllocPages(size))
+
   sysAssert((cast[ByteAddress](result) and PageMask) == 0, "requestOsChunks 1")
   #zeroMem(result, size)
   result.next = nil
@@ -432,6 +449,9 @@ proc getBigChunk(a: var MemRegion, size: int): PBigChunk =
       splitChunk(a, result, size)
     else:
       result = requestOsChunks(a, size)
+      # if we over allocated split the chunk:
+      if result.size > size:
+        splitChunk(a, result, size)
   result.prevSize = 0 # XXX why is this needed?
   result.used = true
   incl(a, a.chunkStarts, pageIndex(result))
diff --git a/tests/system/tdeepcopy.nim b/tests/system/tdeepcopy.nim
index 5a582425a..f7a6e87fa 100644
--- a/tests/system/tdeepcopy.nim
+++ b/tests/system/tdeepcopy.nim
@@ -1,6 +1,5 @@
 discard """
   output: "ok"
-  disabled: "true"
 """
 
 import tables, lists
diff --git a/tests/system/trealloc.nim b/tests/system/trealloc.nim
new file mode 100644
index 000000000..dc5f712d6
--- /dev/null
+++ b/tests/system/trealloc.nim
@@ -0,0 +1,21 @@
+discard """
+  output: '''success'''
+"""
+
+# bug #4818
+
+# Test that this completes without OOM.
+
+const BUFFER_SIZE = 5000
+var buffer = cast[ptr uint16](alloc(BUFFER_SIZE))
+
+var total_size: int64 = 0
+for i in 0 .. 4000:
+    let size = BUFFER_SIZE * i
+    #echo "requesting ", size
+    total_size += size.int64
+    buffer = cast[ptr uint16](realloc(buffer, size))
+    #echo totalSize, " total: ", getTotalMem(), " occupied: ", getOccupiedMem(), " free: ", getFreeMem()
+
+dealloc(buffer)
+echo "success"