Skip to content

[Ruby] Increase in memory footprint in 3.15 #8337

@robertlaurin

Description

@robertlaurin

What version of protobuf and what language are you using?
Version: v3.15.1
Language: Ruby

What operating system (Linux, Windows, ...) and version?
macOS Big Sur Version 11.2.1

What runtime / compiler are you using (e.g., python version or gcc version)
ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-darwin19]

What did you do?

Used a minimal script with opentelemetry-ruby to recreate what was observed in production, this script does require a collector running to demonstrate the issue.

require 'bundler/inline'

gemfile(true) do
  source 'https://rubygems.org'

  gem 'google-protobuf', ENV['GOOGLE_PROTOBUF_VERSION']
  gem 'heap-profiler'
  gem 'opentelemetry-api'
  gem 'opentelemetry-sdk'
  gem 'opentelemetry-exporter-otlp'
end

require 'heap-profiler'
require 'opentelemetry-api'
require 'opentelemetry-sdk'
require 'opentelemetry-exporter-otlp'

HeapProfiler.report("heap_output-protobuf-v-#{Gem.loaded_specs['google-protobuf'].version}") do
  span_processor = OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
    OpenTelemetry::Exporter::OTLP::Exporter.new(
      endpoint: 'http://localhost:55681/v1/trace'
    ),
  )

  OpenTelemetry::SDK.configure do |c|
    c.service_name = 'protobuf-mem-usage'
    c.add_span_processor(span_processor)
  end

  TestTracer = OpenTelemetry.tracer_provider.tracer('protobuf-mem-usage')

  1..10_000.times do
    TestTracer.in_span('parent') do
      1..100.times { TestTracer.in_span('child') {} }
    end
  end
end

What did you expect to see
Using google-protobuf 3.14

heap-profiler heap_output-protobuf-v-3.14.0/
Total allocated: 2.32 GB (22915749 objects)
Total retained: 2.54 MB (17341 objects)
retained memory by class
-----------------------------------
   1.05 MB  Thread
 399.55 kB  OpenTelemetry::SDK::Trace::Span
 358.10 kB  Time
 203.60 kB  String
 166.56 kB  OpenTelemetry::Trace::SpanContext
 150.12 kB  Thread::Mutex
  94.21 kB  OpenTelemetry::SDK::Trace::SpanData
  87.26 kB  Hash
  22.44 kB  Array
   2.08 kB  <ment> (IMEMO)
  344.00 B  Net::HTTP
  280.00 B  Google::Protobuf::RepeatedField
  232.00 B  File
  160.00 B  Proc
  144.00 B  OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor
  128.00 B  Enumerator
  120.00 B  URI::HTTP
  120.00 B  OpenTelemetry::SDK::Trace::TracerProvider
  120.00 B  OpenTelemetry::Exporter::OTLP::Exporter
  120.00 B  Net::HTTP::Post
  120.00 B  Logger::LogDevice
   88.00 B  Net::BufferedIO
   80.00 B  OpenTelemetry::SDK::Trace::Tracer
   80.00 B  OpenTelemetry::SDK::Resources::Resource
   80.00 B  Logger
   80.00 B  <env> (IMEMO)
   56.00 B  Thread::ConditionVariable
   40.00 B  OpenTelemetry::Trace::Span
   40.00 B  OpenTelemetry::SDK::Trace::TracerProvider::Key
   40.00 B  OpenTelemetry::SDK::Trace::NoopSpanProcessor
   40.00 B  OpenTelemetry::SDK::InstrumentationLibrary
   40.00 B  OpenTelemetry::SDK::Baggage::Manager
   40.00 B  OpenTelemetry::Context::Propagation::CompositePropagator
   40.00 B  OpenTelemetry::Context
   40.00 B  Logger::Formatter
   40.00 B  <svar> (IMEMO)

What did you see instead?
Using google-protobuf 3.15.1

heap-profiler heap_output-protobuf-v-3.15.1/
Total allocated: 2.30 GB (22584230 objects)
Total retained: 19.02 MB (356022 objects)
retained memory by class
-----------------------------------
   6.66 MB  Google::Protobuf::Internal::Arena
   4.56 MB  Opentelemetry::Proto::Trace::V1::Status
   4.56 MB  Opentelemetry::Proto::Trace::V1::Span
   1.05 MB  Thread
 396.78 kB  Hash
 393.22 kB  OpenTelemetry::SDK::Trace::Span
 352.43 kB  Time
 219.30 kB  String
 163.92 kB  OpenTelemetry::Trace::SpanContext
 147.74 kB  Thread::Mutex
 110.44 kB  Rational
  94.21 kB  OpenTelemetry::SDK::Trace::SpanData
  80.14 kB  Opentelemetry::Proto::Common::V1::KeyValue
  80.14 kB  Opentelemetry::Proto::Common::V1::AnyValue
  55.74 kB  Array
  36.88 kB  <ifunc> (IMEMO)
  18.40 kB  <memo> (IMEMO)
   8.90 kB  Opentelemetry::Proto::Trace::V1::ResourceSpans
   8.90 kB  Opentelemetry::Proto::Trace::V1::InstrumentationLibrarySpans
   8.90 kB  Opentelemetry::Proto::Resource::V1::Resource
   8.90 kB  Opentelemetry::Proto::Common::V1::InstrumentationLibrary
   8.90 kB  Opentelemetry::Proto::Collector::Trace::V1::ExportTraceServiceRequest
   2.08 kB  <ment> (IMEMO)
  344.00 B  Net::HTTP
  232.00 B  File
  160.00 B  Proc
  144.00 B  OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor
  128.00 B  Enumerator
  120.00 B  URI::HTTP
  120.00 B  OpenTelemetry::SDK::Trace::TracerProvider
  120.00 B  OpenTelemetry::Exporter::OTLP::Exporter
  120.00 B  Net::HTTP::Post
  120.00 B  Logger::LogDevice
   88.00 B  Net::BufferedIO
   88.00 B  <select_set> (DATA)
   80.00 B  OpenTelemetry::SDK::Trace::Tracer
   80.00 B  OpenTelemetry::SDK::Resources::Resource
   80.00 B  Logger
   80.00 B  <throw_data> (IMEMO)
   80.00 B  <env> (IMEMO)
   56.00 B  Thread::ConditionVariable
   40.00 B  OpenTelemetry::Trace::Span
   40.00 B  OpenTelemetry::SDK::Trace::TracerProvider::Key
   40.00 B  OpenTelemetry::SDK::Trace::NoopSpanProcessor
   40.00 B  OpenTelemetry::SDK::InstrumentationLibrary
   40.00 B  OpenTelemetry::SDK::Baggage::Manager
   40.00 B  OpenTelemetry::Context::Propagation::CompositePropagator
   40.00 B  OpenTelemetry::Context
   40.00 B  Logger::Formatter

Anything else we should know about your project / environment
I have had multiple reports of application owners having to revert the google-protobuf gem from 3.15 to 3.14 after seeing their applications double their memory usage, and hitting their limits.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions