/// <summary> /// Deallocates a previously allocated block. /// </summary> /// <param name="address">The address of the block to deallocate.</param> public void Free(uint address) { HeapEntry entry = new HeapEntry(address, 0); int index = blocks.BinarySearch(entry, entryComparer); if (index >= 0) { // delete the block entry = blocks[index]; blocks.RemoveAt(index); // adjust the heap extent if necessary if (entry.Start + entry.Length - heapAddress == heapExtent) { if (index == 0) { heapExtent = 0; } else { HeapEntry prev = blocks[index - 1]; heapExtent = prev.Start + prev.Length - heapAddress; } } // add the block to the free list index = ~freeList.BinarySearch(entry, entryComparer); System.Diagnostics.Debug.Assert(index >= 0); freeList.Insert(index, entry); if (index < freeList.Count - 1) { Coalesce(index, index + 1); } if (index > 0) { Coalesce(index - 1, index); } // shrink the heap if necessary if (blocks.Count > 0 && heapExtent <= (endMem - heapAddress) / 2) { if (setEndMem(heapAddress + heapExtent)) { endMem = heapAddress + heapExtent; for (int i = freeList.Count - 1; i >= 0; i--) { if (freeList[i].Start >= endMem) { freeList.RemoveAt(i); } } } } } }
private void Coalesce(int index1, int index2) { HeapEntry first = freeList[index1]; HeapEntry second = freeList[index2]; if (first.Start + first.Length >= second.Start) { first.Length = second.Start + second.Length - first.Start; freeList[index1] = first; freeList.RemoveAt(index2); } }
/// <summary> /// Allocates a new block on the heap. /// </summary> /// <param name="size">The size of the new block, in bytes.</param> /// <returns>The address of the new block, or 0 if allocation failed.</returns> public uint Alloc(uint size) { HeapEntry result = new HeapEntry(0, size); // look for a free block if (freeList != null) { for (int i = 0; i < freeList.Count; i++) { HeapEntry entry = freeList[i]; if (entry.Length >= size) { result.Start = entry.Start; if (entry.Length > size) { // shrink the free block entry.Start += size; entry.Length -= size; freeList[i] = entry; } else { freeList.RemoveAt(i); } break; } } } if (result.Start == 0) { // enforce maximum heap size if (maxHeapExtent != 0 && heapExtent + size > maxHeapExtent) { return(0); } // add a new block at the end result = new HeapEntry(heapAddress + heapExtent, size); if (heapAddress + heapExtent + size > endMem) { // grow the heap uint newHeapAllocation = Math.Max( heapExtent * 5 / 4, heapExtent + size); if (maxHeapExtent != 0) { newHeapAllocation = Math.Min(newHeapAllocation, maxHeapExtent); } if (setEndMem(heapAddress + newHeapAllocation)) { endMem = heapAddress + newHeapAllocation; } else { return(0); } } heapExtent += size; } // add the new block to the list int index = ~blocks.BinarySearch(result, entryComparer); System.Diagnostics.Debug.Assert(index >= 0); blocks.Insert(index, result); return(result.Start); }