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)