diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/Connection.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/Connection.cs
index 814da8143b..add23c4389 100644
--- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/Connection.cs
+++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/Connection.cs
@@ -253,7 +253,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
var result = _rawSocketInput.IncomingStart();
return handle.Libuv.buf_init(
- result.Pin() + result.End,
+ result.DataArrayPtr + result.End,
result.Data.Offset + result.Data.Count - result.End);
}
diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/SocketOutput.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/SocketOutput.cs
index f424a7531c..5db2fb3ebc 100644
--- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/SocketOutput.cs
+++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/SocketOutput.cs
@@ -684,14 +684,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
var end = _lockedEnd.Block;
if (block == end)
{
- end.Unpin();
return;
}
while (block.Next != end)
{
block = block.Next;
- block.Unpin();
}
block.Next = null;
@@ -705,7 +703,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
var returnBlock = block;
block = block.Next;
- returnBlock.Unpin();
returnBlock.Pool.Return(returnBlock);
}
}
diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/MemoryPool.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/MemoryPool.cs
index d5a4e59b7e..6fd37f8a9c 100644
--- a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/MemoryPool.cs
+++ b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/MemoryPool.cs
@@ -63,24 +63,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
///
/// Called to take a block from the pool.
///
- /// The block returned must be at least this size. It may be larger than this minimum size, and if so,
- /// the caller may write to the block's entire size rather than being limited to the minumumSize requested.
/// The block that is reserved for the called. It must be passed to Return when it is no longer being used.
- public MemoryPoolBlock Lease(int minimumSize = MaxPooledBlockLength)
+ public MemoryPoolBlock Lease()
{
- if (minimumSize > _blockLength)
- {
- // The requested minimumSize is actually larger then the usable memory of a single block.
- // Because this is the degenerate case, a one-time-use byte[] array and tracking object are allocated.
- // When this block tracking object is returned it is not added to the pool - instead it will be
- // allowed to be garbage collected normally.
- return MemoryPoolBlock.Create(
- new ArraySegment(new byte[minimumSize]),
- dataPtr: IntPtr.Zero,
- pool: this,
- slab: null);
- }
-
MemoryPoolBlock block;
if (_blocks.TryDequeue(out block))
{
diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/MemoryPoolBlock.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/MemoryPoolBlock.cs
index 25cab8c4f4..362165ee12 100644
--- a/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/MemoryPoolBlock.cs
+++ b/src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/MemoryPoolBlock.cs
@@ -11,18 +11,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
///
public class MemoryPoolBlock
{
- ///
- /// If this block represents a one-time-use memory object, this GCHandle will hold that memory object at a fixed address
- /// so it can be used in native operations.
- ///
- private GCHandle _pinHandle;
-
///
/// Native address of the first byte of this block's Data memory. It is null for one-time-use memory, or copied from
/// the Slab's ArrayPtr for a slab-block segment. The byte it points to corresponds to Data.Array[0], and in practice you will always
- /// use the _dataArrayPtr + Start or _dataArrayPtr + End, which point to the start of "active" bytes, or point to just after the "active" bytes.
+ /// use the DataArrayPtr + Start or DataArrayPtr + End, which point to the start of "active" bytes, or point to just after the "active" bytes.
///
- private IntPtr _dataArrayPtr;
+ public readonly IntPtr DataArrayPtr;
///
/// The array segment describing the range of memory this block is tracking. The caller which has leased this block may only read and
@@ -33,8 +27,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
///
/// This object cannot be instantiated outside of the static Create method
///
- protected MemoryPoolBlock()
+ protected MemoryPoolBlock(IntPtr dataArrayPtr)
{
+ DataArrayPtr = dataArrayPtr;
}
///
@@ -76,20 +71,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
~MemoryPoolBlock()
{
- Debug.Assert(!_pinHandle.IsAllocated, "Ad-hoc memory block wasn't unpinned");
Debug.Assert(Slab == null || !Slab.IsActive, "Block being garbage collected instead of returned to pool");
- if (_pinHandle.IsAllocated)
- {
- // if this is a one-time-use block, ensure that the GCHandle does not leak
- _pinHandle.Free();
- }
-
if (Slab != null && Slab.IsActive)
{
- Pool.Return(new MemoryPoolBlock
+ Pool.Return(new MemoryPoolBlock(DataArrayPtr)
{
- _dataArrayPtr = _dataArrayPtr,
Data = Data,
Pool = Pool,
Slab = Slab,
@@ -97,49 +84,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
}
}
- ///
- /// Called to ensure that a block is pinned, and return the pointer to the native address
- /// of the first byte of this block's Data memory. Arriving data is read into Pin() + End.
- /// Outgoing data is read from Pin() + Start.
- ///
- ///
- public IntPtr Pin()
- {
- Debug.Assert(!_pinHandle.IsAllocated);
-
- if (_dataArrayPtr != IntPtr.Zero)
- {
- // this is a slab managed block - use the native address of the slab which is always locked
- return _dataArrayPtr;
- }
- else
- {
- // this is one-time-use memory - lock the managed memory until Unpin is called
- _pinHandle = GCHandle.Alloc(Data.Array, GCHandleType.Pinned);
- return _pinHandle.AddrOfPinnedObject();
- }
- }
-
- public void Unpin()
- {
- if (_dataArrayPtr == IntPtr.Zero)
- {
- // this is one-time-use memory - unlock the managed memory
- Debug.Assert(_pinHandle.IsAllocated);
- _pinHandle.Free();
- }
- }
-
- public static MemoryPoolBlock Create(
+ internal static MemoryPoolBlock Create(
ArraySegment data,
IntPtr dataPtr,
MemoryPool pool,
MemoryPoolSlab slab)
{
- return new MemoryPoolBlock
+ return new MemoryPoolBlock(dataPtr)
{
Data = data,
- _dataArrayPtr = dataPtr,
Pool = pool,
Slab = slab,
Start = data.Offset,
diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Networking/UvWriteReq.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Networking/UvWriteReq.cs
index bf088950a5..bc776767a6 100644
--- a/src/Microsoft.AspNetCore.Server.Kestrel/Networking/UvWriteReq.cs
+++ b/src/Microsoft.AspNetCore.Server.Kestrel/Networking/UvWriteReq.cs
@@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
// create and pin each segment being written
pBuffers[index] = Libuv.buf_init(
- block.Pin() + blockStart,
+ block.DataArrayPtr + blockStart,
blockEnd - blockStart);
block = block.Next;
@@ -89,7 +89,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Networking
var block = start.Block;
for (var index = 0; index < nBuffers; index++)
{
- block.Unpin();
block = block.Next;
}