/// <summary> /// Start a new allocator. /// This tracks memory usage, but does not do any physical work /// </summary> /// <param name="start">Start of space (bytes) available to the allocator. Some will be reserved for arena tracking</param> /// <param name="limit">Maximum memory before an out-of-memory condition is flagged (bytes)</param> /// <param name="memory">Access to real or simulated memory</param> public Allocator(long start, long limit, [NotNull] IMemoryAccess memory) { _limit = limit; _memory = memory; // with 64KB arenas (ushort) and 1GB of RAM, we get 16384 arenas. // recording only heads and refs would take 64KB of management space // recording heads, refs and back-step (an optimisation for very short-lived items) would use 96KB of management space. // This seems pretty reasonable. _arenaCount = (int)((_limit - _start) / ArenaSize); _currentArena = 0; // Allow space for arena tables, store adjusted base var sizeOfTables = sizeof(ushort) * _arenaCount; _headsPtr = start; _refCountsPtr = start + sizeOfTables; _start = start + (sizeOfTables * 2); // zero-out the tables var zptr = _headsPtr; while (zptr < _start) { _memory.Write <ushort>(zptr, 0); zptr += sizeof(ushort); } }
private Result <long> NewChunk() { var res = _alloc.Alloc(ChunkBytes); if (!res.Success) { return(Result.Fail <long>()); } if (res.Value < 0) { return(Result.Fail <long>()); } var ptr = res.Value; _mem.Write <long>(ptr, -1); // set the continuation pointer of the new chunk to invalid if (_endChunkPtr >= 0) { _mem.Write(_endChunkPtr, ptr); // update the continuation pointer of the old end chunk } _endChunkPtr = ptr; // update the end chunk pointer _skipTableDirty = true; return(Result.Ok(ptr)); }
private void SetHead(int arenaIndex, ushort val) { _memory.Write <ushort>(_headsPtr + (arenaIndex * sizeof(ushort)), val); }
public void SetRootValue(TElement element) { _mem.Write(Root + NODE_HEAD_SIZE, element); }