internal RetainedMemory(Memory <T> memory) { if (MemoryMarshal.TryGetMemoryManager <T, RetainableMemory <T> >(memory, out var manager)) { manager.Increment(); _manager = manager; _start = 0; _length = memory.Length; } else if (MemoryMarshal.TryGetArray <T>(memory, out var segment)) { _manager = ArrayMemory <T> .Create(segment.Array, segment.Offset, segment.Count, externallyOwned : true); _manager.Increment(); _start = 0; _length = _manager.Length; } else { ThrowNotSupportedMemoryType(); _manager = default; _start = 0; _length = 0; } #if DETECT_LEAKS _finalizeChecker = new PanicOnFinalize(); #endif }
public ArrayMemorySliceBucket(int bufferLength, int maxBufferCount) { if (!BitUtil.IsPowerOfTwo(bufferLength) || bufferLength >= Settings.SlabLength) { ThrowHelper.ThrowArgumentException("bufferLength must be a power of two max 64MB"); } _bufferLength = bufferLength; // NOTE: allocateOnEmpty = true _pool = new LockedObjectPool <ArrayMemorySlice <T> >(maxBufferCount, Factory, allocateOnEmpty: true); _slab = ArrayMemory <T> .Create(Settings.SlabLength, true); _slabFreeCount = _slab.Length / _bufferLength; }
internal RetainableMemory <T> CreateNew() { RetainableMemory <T> buffer; if (_pool._disposed) { ThrowDisposed <RetainableMemoryPool <T> >(); } if (_factory == null) { ArrayMemory <T> arrayMemory; if (_pool._pin && _bufferLength * Unsafe.SizeOf <T>() <= Settings.LARGE_BUFFER_LIMIT) { if (_sliceBucket == null) { _sliceBucket = new ArrayMemorySliceBucket <T>(_bufferLength, _buffers.Length); } arrayMemory = _sliceBucket.RentMemory(); } else { arrayMemory = ArrayMemory <T> .Create(_bufferLength, _pool._pin); } arrayMemory._pool = _pool; if (arrayMemory.LengthPow2 != _bufferLength) { // TODO proper exception, this is for args ThrowBadLength(); } buffer = arrayMemory; } else { buffer = _factory.Invoke(_pool, _bufferLength); } if (_pool.IsRentAlwaysClean) { buffer.GetSpan().Clear(); } return(buffer); }
public unsafe ArrayMemorySlice(ArrayMemory <T> slab, LockedObjectPool <ArrayMemorySlice <T> > slicesPool, int offset, int length) { if (!TypeHelper <T> .IsPinnable) { ThrowHelper.FailFast("Do not use slices for not pinnable"); } #pragma warning disable 618 _slab = slab; _slab.Increment(); _pointer = Unsafe.Add <T>(_slab.Pointer, offset); _handle = GCHandle.Alloc(_slab); #pragma warning restore 618 _slicesPool = slicesPool; _length = length; _array = slab._array; _arrayOffset = slab._arrayOffset + offset; }
private ArrayMemorySlice <T> Factory() { // the whole purpose is pooling of ArrayMemorySlice, it's OK to lock lock (_pool) { if (_slabFreeCount == 0) { // drop previous slab, it is owned by previous slices // and will be returned to the pool when all slices are disposed _slab = ArrayMemory <T> .Create(Settings.SlabLength, true); _slabFreeCount = _slab.Length / _bufferLength; } var offset = _slab.Length - _slabFreeCount-- *_bufferLength; var slice = new ArrayMemorySlice <T>(_slab, _pool, offset, _bufferLength); return(slice); } }
public RetainedMemory(Memory <T> memory, bool pin = true) // TODO pin param added later and before it behaved like with true, but better to change to false and review usage { if (MemoryMarshal.TryGetMemoryManager <T, RetainableMemory <T> >(memory, out var manager)) { if (!manager.IsPinned && pin) { // TODO review. This uses implementation detail of RetainableMemory: // if pointer is null then it is an non-pinned array for which we did not create // a GCHandle (very expensive). Call to Pin() checks if pointer is null and // creates a GCHandle + pointer. Try to avoid pinning non-pooled ArrayMemory // because it is very expensive. manager.Pin(); } else { manager.Increment(); } _manager = manager; _offset = 0; _length = memory.Length; } else if (MemoryMarshal.TryGetArray <T>(memory, out var segment)) { _manager = ArrayMemory <T> .Create(segment.Array, segment.Offset, segment.Count, externallyOwned : true, pin); _manager.Increment(); _offset = 0; _length = _manager.Length; } else { ThrowNotSupportedMemoryType(); _manager = default; _offset = 0; _length = 0; } #if DETECT_LEAKS _finalizeChecker = new PanicOnFinalize(); #endif }
public Memory <byte> GetMemory() { CheckDisposed(); if (!_largeBuffer.IsEmpty) { return(_largeBuffer.Memory.Slice(0, checked ((int)_length))); } if (_blocks.Count == 1) { return(_blocks[0]); } // Memory needs to reflect the capacity, not the length, because // it's possible that people will manipulate the buffer directly // and set the length afterward. Capacity sets the expectation // for the size of the buffer. #if DEBUG var newBuffer = _memoryManager.GetLargeBuffer(Capacity, _tag); #else var newBuffer = _memoryManager.GetLargeBuffer(Capacity, null); #endif // InternalRead will check for existence of largeBuffer, so make sure we // don't set it until after we've copied the data. InternalRead(newBuffer, 0, _length, 0); _largeBuffer = ArrayMemory <byte> .Create(newBuffer).Retain(); if (_blocks.Count > 0) { #if DEBUG _memoryManager.ReturnBlocks(_blocks, _tag); #else _memoryManager.ReturnBlocks(_blocks, null); #endif _blocks.Clear(); } return(_largeBuffer.Memory.Slice(0, checked ((int)_length))); }
private RetainableMemory <T> CreateNew(int length) { if (_disposed) { ThrowDisposed <RetainableMemoryPool <T> >(); } if (_factory == null) { var am = ArrayMemory <T> .Create(BufferPool <T> .Rent(length), 0, length, false, _pin, this); // am._pool = this; return(Unsafe.As <RetainableMemory <T> >(am)); } var buffer = _factory.Invoke(this, length); if (IsRentAlwaysClean) { buffer.GetSpan().Clear(); } return(buffer); }