Pin frozen messages to their arena to prevent garbage collection.
diff --git a/ruby/lib/google/protobuf/ffi/internal/arena.rb b/ruby/lib/google/protobuf/ffi/internal/arena.rb index 757a84f..e5caa4d 100644 --- a/ruby/lib/google/protobuf/ffi/internal/arena.rb +++ b/ruby/lib/google/protobuf/ffi/internal/arena.rb
@@ -35,6 +35,7 @@ module Protobuf module Internal class Arena + attr :pinned_messages # FFI Interface methods and setup extend ::FFI::DataConverter @@ -59,6 +60,7 @@ def initialize(pointer) @arena = ::FFI::AutoPointer.new(pointer, Google::Protobuf::FFI.method(:free_arena)) + @pinned_messages = [] end def fuse(other_arena) @@ -67,6 +69,10 @@ raise RuntimeError.new "Unable to fuse arenas. This should never happen since Ruby does not use initial blocks" end end + + def pin(message) + pinned_messages.push message + end end end
diff --git a/ruby/lib/google/protobuf/ffi/message.rb b/ruby/lib/google/protobuf/ffi/message.rb index 9ec5bc1..43bd2b2 100644 --- a/ruby/lib/google/protobuf/ffi/message.rb +++ b/ruby/lib/google/protobuf/ffi/message.rb
@@ -80,6 +80,11 @@ instance end + def freeze + super + @arena.pin self + end + def dup duplicate = self.class.private_constructor(@arena) mini_table = Google::Protobuf::FFI.get_mini_table(self.class.descriptor)