Skip to content

Add a PooledMemoryStream to avoid allocating#1275

Merged
adamhathcock merged 22 commits intomasterfrom
adam/pooledmemorystream
Apr 19, 2026
Merged

Add a PooledMemoryStream to avoid allocating#1275
adamhathcock merged 22 commits intomasterfrom
adam/pooledmemorystream

Conversation

@adamhathcock
Copy link
Copy Markdown
Owner

This pull request introduces the new PooledMemoryStream class to the codebase and systematically replaces usages of MemoryStream with PooledMemoryStream in performance-critical paths. This change is aimed at reducing memory allocations and improving performance by reusing buffers. Additionally, comprehensive unit tests for PooledMemoryStream have been added, and a minor helper method was introduced in ThrowHelper. There are also minor dependency downgrades in the project lock file.

Memory Stream Refactoring:

  • Replaced all instances of MemoryStream with PooledMemoryStream in core archive and compression logic, including TAR, SevenZip, LZMA, PPMd, and Squeezed stream handling (TarArchive.cs, TarArchive.Async.cs, SevenZipFilesInfo.cs, ArchiveReader.cs, Lzma2EncoderStream.cs, PpmdStream.cs, SqueezedStream.cs, SqueezedStream.Async.cs, SevenZipWriter.cs). [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13]

  • Added necessary using SharpCompress.IO; directives to files using PooledMemoryStream. [1] [2] [3] [4] [5]

New Features and Testing:

  • Added a comprehensive test suite for PooledMemoryStream in PooledMemoryStreamTests.cs, testing buffer management, disposal, capacity adjustments, and API behavior.

Utilities:

  • Added ThrowIfGreaterThan(long value, long other, string? paramName = null) to ThrowHelper for improved argument validation.

Dependency Updates:

  • Downgraded Microsoft.NET.ILLink.Tasks package versions in packages.lock.json for .NET 8.0 and .NET 10.0 targets. [1] [2]

Copilot AI review requested due to automatic review settings April 4, 2026 10:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces PooledMemoryStream (a MemoryStream-compatible implementation backed by ArrayPool<byte>) and refactors performance-critical code paths to use it instead of allocating new MemoryStream buffers, with accompanying unit tests and a small ThrowHelper addition.

Changes:

  • Added src/SharpCompress/IO/PooledMemoryStream.cs plus a dedicated test suite in PooledMemoryStreamTests.cs.
  • Replaced various MemoryStream usages with PooledMemoryStream across TAR, 7z, LZMA2, PPMd, and Squeezed stream handling.
  • Added ThrowHelper.ThrowIfGreaterThan(long, long, ...) and updated packages.lock.json (ILLink tasks versions).

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs Adds behavioral tests for pooled buffer growth, disposal/pool returns, buffer exposure, capacity changes, and disposed behavior.
src/SharpCompress/IO/PooledMemoryStream.cs Implements pooled/segmented + contiguous modes and overrides key MemoryStream APIs to reduce allocations.
src/SharpCompress/Writers/SevenZip/SevenZipWriter.cs Uses PooledMemoryStream for temporary header streams during 7z finalization.
src/SharpCompress/Archives/Tar/TarArchive.cs Uses PooledMemoryStream while decoding TAR header name data.
src/SharpCompress/Archives/Tar/TarArchive.Async.cs Async equivalent TAR header decoding now uses PooledMemoryStream.
src/SharpCompress/Common/SevenZip/SevenZipFilesInfo.cs Uses PooledMemoryStream for buffering 7z file property payloads.
src/SharpCompress/Common/SevenZip/ArchiveReader.cs Replaces an internal MemoryStream allocation with PooledMemoryStream for 7z reading.
src/SharpCompress/Compressors/LZMA/Lzma2EncoderStream.cs Uses PooledMemoryStream for temporary LZMA encode/decode buffers.
src/SharpCompress/Compressors/PPMd/PpmdStream.cs Uses PooledMemoryStream in PPMd finalization path (EOF encode).
src/SharpCompress/Compressors/Squeezed/SqueezedStream.cs Uses PooledMemoryStream for Huffman-decoded buffer and invalid-header empty stream.
src/SharpCompress/Compressors/Squeezed/SqueezedStream.Async.cs Async Squeezed implementation mirrors PooledMemoryStream usage.
src/SharpCompress/ThrowHelper.cs Adds a long overload for ThrowIfGreaterThan.
src/SharpCompress/packages.lock.json Downgrades Microsoft.NET.ILLink.Tasks resolved/requested versions for net8.0 and net10.0.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment thread src/SharpCompress/Compressors/PPMd/PpmdStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 5, 2026 13:10
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 5, 2026 13:16
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs
… in PooledMemoryStream

Agent-Logs-Url: https://github.com/adamhathcock/sharpcompress/sessions/1f2c3c48-1112-43f1-82ce-efb157fbe0d5

Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 5, 2026 13:47
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/SharpCompress.csproj
Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 5, 2026 13:57
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/SharpCompress.csproj
Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs Outdated
Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs Outdated
Comment thread src/SharpCompress/Writers/SevenZip/SevenZipWriter.cs
Copilot AI review requested due to automatic review settings April 19, 2026 10:49
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 10 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs Outdated
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment on lines +174 to 175
using var headerStream = new PooledMemoryStream();
ArchiveHeaderWriter.WriteRawHeader(headerStream, mainStreamsInfo, filesInfo);
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

headerStream is now a PooledMemoryStream, but the raw-header path later computes a CRC via rawHeaderStream.GetBuffer().AsSpan(0, (int)Length). Since PooledMemoryStream.GetBuffer() allocates a fresh array sized to Capacity, this can introduce extra allocations proportional to capacity and undermine the pooling benefit. Consider switching CRC calculation to use a Length-sized buffer or a non-allocating path.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit f8485b0. Both WriteCompressedHeader and WriteRawHeaderToOutput now compute the CRC by writing the stream's blocks directly into a Crc32Stream(Stream.Null) sink via WriteTo(), which avoids allocating any contiguous buffer.

Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs Outdated
Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs Outdated
Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs Outdated
Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs Outdated
Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 19, 2026 11:18
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +194 to 195
using var output = new PooledMemoryStream();
decoder.Code(input, output, compressedData.Length, uncompressedSize, null);
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FindConsumedBytes doesn’t use the decompressed output; it only needs input.Position after decoder.Code(...). Using PooledMemoryStream here adds pooling overhead and can rent/return buffers unnecessarily. Use Stream.Null (or another sink stream) for output instead.

Suggested change
using var output = new PooledMemoryStream();
decoder.Code(input, output, compressedData.Length, uncompressedSize, null);
decoder.Code(input, Stream.Null, compressedData.Length, uncompressedSize, null);

Copilot uses AI. Check for mistakes.
Comment thread src/SharpCompress/packages.lock.json
Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs
Comment thread src/SharpCompress/Writers/SevenZip/SevenZipWriter.cs
Comment thread tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
Comment thread src/SharpCompress/IO/PooledMemoryStream.cs
@adamhathcock adamhathcock enabled auto-merge April 19, 2026 13:56
@adamhathcock adamhathcock merged commit 8bd386c into master Apr 19, 2026
7 checks passed
@adamhathcock adamhathcock deleted the adam/pooledmemorystream branch April 19, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants