From 7fc5c0e56577c912024987fc39f2bb853fc149a1 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Fri, 16 Oct 2026 15:44:44 +0100 Subject: [PATCH] Use pooled memory streams for temporary production buffers --- .../Compressors/ArcLzw/ArcLzwStream.Async.cs | 2 +- src/SharpCompress/Compressors/ArcLzw/ArcLzwStream.cs | 4 ++-- src/SharpCompress/Compressors/PPMd/PpmdStream.cs | 3 ++- .../Compressors/Shrink/ShrinkStream.Async.cs | 3 ++- src/SharpCompress/Compressors/Shrink/ShrinkStream.cs | 3 ++- .../Writers/SevenZip/SevenZipWriter.Async.cs | 8 ++++---- src/SharpCompress/Writers/Zip/ZipWriter.Async.cs | 7 ++++--- 7 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/SharpCompress/Compressors/ArcLzw/ArcLzwStream.Async.cs b/src/SharpCompress/Compressors/ArcLzw/ArcLzwStream.Async.cs index 3ab2030b..96d6da7d 100644 --- a/src/SharpCompress/Compressors/ArcLzw/ArcLzwStream.Async.cs +++ b/src/SharpCompress/Compressors/ArcLzw/ArcLzwStream.Async.cs @@ -25,7 +25,7 @@ public partial class ArcLzwStream if (!_processed) { using var limited = new ReadOnlySubStream(_stream, _compressedSize); - using var data = new MemoryStream(); + using var data = new PooledMemoryStream(); await limited.CopyToAsync(data, 81920, cancellationToken).ConfigureAwait(false); FinishDecompression(data); } diff --git a/src/SharpCompress/Compressors/ArcLzw/ArcLzwStream.cs b/src/SharpCompress/Compressors/ArcLzw/ArcLzwStream.cs index c0f763dd..10a32111 100644 --- a/src/SharpCompress/Compressors/ArcLzw/ArcLzwStream.cs +++ b/src/SharpCompress/Compressors/ArcLzw/ArcLzwStream.cs @@ -191,7 +191,7 @@ public partial class ArcLzwStream : Stream if (!_processed) { using var limited = new ReadOnlySubStream(_stream, _compressedSize); - using var data = new MemoryStream(); + using var data = new PooledMemoryStream(); limited.CopyTo(data); FinishDecompression(data); } @@ -201,7 +201,7 @@ public partial class ArcLzwStream : Stream return result; } - private void FinishDecompression(MemoryStream data) + private void FinishDecompression(PooledMemoryStream data) { if (data.Length != _compressedSize) { diff --git a/src/SharpCompress/Compressors/PPMd/PpmdStream.cs b/src/SharpCompress/Compressors/PPMd/PpmdStream.cs index b48cf4cf..ad958fa4 100644 --- a/src/SharpCompress/Compressors/PPMd/PpmdStream.cs +++ b/src/SharpCompress/Compressors/PPMd/PpmdStream.cs @@ -202,7 +202,8 @@ public class PpmdStream : Stream, IAsyncDisposable _isDisposed = true; if (_compress) { - await _model.EncodeBlockAsync(_stream, new MemoryStream(), true).ConfigureAwait(false); + using var input = new PooledMemoryStream(); + await _model.EncodeBlockAsync(_stream, input, true).ConfigureAwait(false); } _modelH?.Dispose(); _modelH = null; diff --git a/src/SharpCompress/Compressors/Shrink/ShrinkStream.Async.cs b/src/SharpCompress/Compressors/Shrink/ShrinkStream.Async.cs index 49895df3..5d6f7e61 100644 --- a/src/SharpCompress/Compressors/Shrink/ShrinkStream.Async.cs +++ b/src/SharpCompress/Compressors/Shrink/ShrinkStream.Async.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Threading; using System.Threading.Tasks; +using SharpCompress.IO; namespace SharpCompress.Compressors.Shrink; @@ -28,7 +29,7 @@ internal partial class ShrinkStream : Stream // Read actual compressed data from the stream rather than pre-allocating based on the // declared compressed size, which may be crafted to cause an OutOfMemoryException. // The stream is already bounded by ReadOnlySubStream in ZipFilePart. - using var srcMs = new MemoryStream(); + using var srcMs = new PooledMemoryStream(); await _inStream.CopyToAsync(srcMs, 81920, cancellationToken).ConfigureAwait(false); var src = srcMs.ToArray(); // Decompress synchronously (CPU-bound operation). diff --git a/src/SharpCompress/Compressors/Shrink/ShrinkStream.cs b/src/SharpCompress/Compressors/Shrink/ShrinkStream.cs index a1f34259..51ee203d 100644 --- a/src/SharpCompress/Compressors/Shrink/ShrinkStream.cs +++ b/src/SharpCompress/Compressors/Shrink/ShrinkStream.cs @@ -1,6 +1,7 @@ using System; using System.IO; using SharpCompress.Common; +using SharpCompress.IO; namespace SharpCompress.Compressors.Shrink; @@ -52,7 +53,7 @@ internal partial class ShrinkStream : Stream // Read actual compressed data from the stream rather than pre-allocating based on the // declared compressed size, which may be crafted to cause an OutOfMemoryException. // The stream is already bounded by ReadOnlySubStream in ZipFilePart. - using var srcMs = new MemoryStream(); + using var srcMs = new PooledMemoryStream(); _inStream.CopyTo(srcMs); var src = srcMs.ToArray(); Decode(src); diff --git a/src/SharpCompress/Writers/SevenZip/SevenZipWriter.Async.cs b/src/SharpCompress/Writers/SevenZip/SevenZipWriter.Async.cs index 9b24371d..ce5b9021 100644 --- a/src/SharpCompress/Writers/SevenZip/SevenZipWriter.Async.cs +++ b/src/SharpCompress/Writers/SevenZip/SevenZipWriter.Async.cs @@ -53,7 +53,7 @@ public partial class SevenZipWriter var filesInfo = new SevenZipFilesInfoWriter { Entries = entries.ToArray() }; // Write header to a temporary stream first - using var headerStream = new MemoryStream(); + using var headerStream = new PooledMemoryStream(); ArchiveHeaderWriter.WriteRawHeader(headerStream, mainStreamsInfo, filesInfo); // Optionally compress the header @@ -68,7 +68,7 @@ public partial class SevenZipWriter } private async ValueTask WriteCompressedHeaderAsync( - MemoryStream rawHeaderStream, + PooledMemoryStream rawHeaderStream, long endOfPackedData ) { @@ -95,7 +95,7 @@ public partial class SevenZipWriter }; // Write encoded header to a second temporary stream - using var encodedHeaderStream = new MemoryStream(); + using var encodedHeaderStream = new PooledMemoryStream(); ArchiveHeaderWriter.WriteEncodedHeader(encodedHeaderStream, headerStreamsInfo); // Write the encoded header to the output @@ -123,7 +123,7 @@ public partial class SevenZipWriter } private async ValueTask WriteRawHeaderToOutputAsync( - MemoryStream rawHeaderStream, + PooledMemoryStream rawHeaderStream, long endOfPackedData ) { diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.Async.cs b/src/SharpCompress/Writers/Zip/ZipWriter.Async.cs index b934c6e1..fbf5ab07 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.Async.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.Async.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using SharpCompress.Common; using SharpCompress.Common.Zip; using SharpCompress.Common.Zip.Headers; +using SharpCompress.IO; namespace SharpCompress.Writers.Zip; @@ -24,7 +25,7 @@ public partial class ZipWriter // Buffer the entire central directory + end record into memory, then write async. // This avoids synchronous writes to the underlying stream during finalization. - using var ms = new MemoryStream(); + using var ms = new PooledMemoryStream(); ulong size = 0; foreach (var entry in entries) { @@ -149,9 +150,9 @@ public partial class ZipWriter CancellationToken cancellationToken ) { - // Build the header synchronously into a MemoryStream, then async-copy to OutputStream. + // Build the header synchronously into a pooled stream, then async-copy to OutputStream. // This avoids any synchronous writes to the potentially async-only output stream. - using var ms = new MemoryStream(); + using var ms = new PooledMemoryStream(); var outputStream = OutputStream.NotNull(); var result = WriteHeader( ms,