Skip to content

[feature request] Improve Protobuff Serialization Strategy: Replace ThreadStatic Array with Segmented IBufferWriter #6396

@paulomorgado

Description

@paulomorgado

Package

OpenTelemetry.Exporter.OpenTelemetryProtocol

Is your feature request related to a problem?

Improve Protobuff Serialization Strategy: Replace ThreadStatic Array with Segmented IBufferWriter<byte>

Description

Currently, the protobuf serialization strategy relies on a ThreadStatic-anchored byte array that grows as needed, involving data copying on each resize. This approach has several limitations in terms of performance, memory efficiency, and scalability.

Proposal

Replace the current buffer implementation with a segmented buffer that:

  • Implements IBufferWriter<byte>
  • Produces a ReadOnlySequence<byte> for downstream consumption

Benefits of Segmented Buffer Approach

✅ Zero-Copy Composition

  • ReadOnlySequence<byte> allows chaining multiple memory segments without copying data.
  • Avoids the overhead of reallocating and copying data as the buffer grows.

✅ Better Memory Utilization

  • Segments can be pooled and reused, reducing GC pressure.
  • Avoids large contiguous allocations, which are more prone to fragmentation and LOH (Large Object Heap) allocations.

✅ Thread Safety and Isolation

  • ThreadStatic buffers are shared across all usages on the same thread, which can lead to subtle bugs or data leaks.
  • A segmented buffer can be scoped per operation, ensuring isolation and correctness.

✅ Scalability

  • Segmented buffers scale better in high-throughput or concurrent environments.
  • They can be backed by ArrayPool<byte> or custom memory pools for fine-grained control.

✅ Compatibility with Pipelines and Span-based APIs

  • IBufferWriter<byte> is the standard interface used by System.IO.Pipelines and other modern .NET APIs.
  • Enables seamless integration with serializers, encoders, and network stacks.

Drawbacks of Current ThreadStatic Array Approach

  • ❌ Requires manual resizing and copying, which is error-prone and inefficient.
  • ❌ Can lead to memory leaks or excessive memory retention if not carefully managed.
  • ❌ Not composable or compatible with modern .NET streaming APIs.

Suggested Implementation

Introduce a PooledSegmentedBufferWriter class that:

  • Implements IBufferWriter<byte>
  • Internally manages a list of pooled segments
  • Exposes a ReadOnlySequence<byte> for reading

What is the expected behavior?

The protobuf serialization process should use a PooledSegmentedBufferWriter to efficiently accumulate serialized data without reallocating or copying memory as the buffer grows. The writer should:

  • Dynamically allocate and reuse pooled memory segments.
  • Implement IBufferWriter<byte> to support efficient, span-based writing.
  • Produce a ReadOnlySequence<byte> that represents the complete serialized payload without requiring additional copying or transformation.
  • Avoid reliance on ThreadStatic buffers, ensuring thread safety and reducing memory retention risks.
  • Integrate seamlessly with existing serialization pipelines and support high-throughput scenarios with minimal GC overhead.

Which alternative solutions or features have you considered?

Alternative 1: ThreadStatic Byte Array with Manual Resizing (Current Implementation)

This approach uses a ThreadStatic-anchored byte array that grows as needed. While it avoids allocations in some cases by reusing the same buffer per thread, it has several drawbacks:

  • Requires manual resizing and copying, which is inefficient and error-prone.
  • Can lead to memory retention issues if buffers grow large and are never reset.
  • Not safe across async boundaries or parallel operations.
  • Difficult to integrate with modern span-based or streaming APIs.

Alternative 2: ArrayPool with Manual Buffer Management

Using ArrayPool<byte> to rent and return buffers is a common way to reduce allocations:

  • Avoids repeated allocations by reusing pooled arrays.
  • Still requires manual resizing and copying when the buffer grows.
  • Does not support segmented composition — the buffer must be contiguous.
  • Managing lifetime and return of the buffer adds complexity and risk of leaks or corruption.

Alternative 3: RecyclableMemoryStream

RecyclableMemoryStream from the Microsoft.IO package is a high-performance, pooled stream implementation that:

  • Implements IBufferWriter<byte> out of the box.
  • Can produce a ReadOnlySequence<byte>.
  • Reduces LOH allocations and GC pressure through segment pooling.

While this is a strong candidate, it introduces an external dependency and adds some complexity in terms of configuration and diagnostics. It also abstracts away some control over segment size and memory layout, which may be important in performance-critical scenarios.

Why PooledSegmentedBufferWriter is the Best Option

  • Offers fine-grained control over segment size, pooling strategy, and memory layout.
  • Fully compatible with IBufferWriter<byte> and ReadOnlySequence<byte>, enabling efficient

Additional context

No response

/cc @Kielek, @martincostello

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestneeds-triageNew issues which have not been classified or triaged by a community memberpkg:OpenTelemetry.Exporter.OpenTelemetryProtocolIssues related to OpenTelemetry.Exporter.OpenTelemetryProtocol NuGet package

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions