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)