Skip to content

Commit 9150795

Browse files
committed
Ruby implement memsize functions for native types
Fix: #10280 This allows Ruby to report a more correct estimation of the memory used by these objects. It's useful when running memory profilers against applications.
1 parent 462964e commit 9150795

4 files changed

Lines changed: 47 additions & 3 deletions

File tree

ruby/ext/google/protobuf_c/map.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,13 @@ static void Map_mark(void* _self) {
6161
rb_gc_mark(self->arena);
6262
}
6363

64+
static size_t Map_memsize(const void* _self) {
65+
return sizeof(Map);
66+
}
67+
6468
const rb_data_type_t Map_type = {
6569
"Google::Protobuf::Map",
66-
{Map_mark, RUBY_DEFAULT_FREE, NULL},
70+
{Map_mark, RUBY_DEFAULT_FREE, Map_memsize},
6771
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
6872
};
6973

ruby/ext/google/protobuf_c/message.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,13 @@ static void Message_mark(void* _self) {
6666
rb_gc_mark(self->arena);
6767
}
6868

69+
static size_t Message_memsize(const void* _self) {
70+
return sizeof(Message);
71+
}
72+
6973
static rb_data_type_t Message_type = {
7074
"Google::Protobuf::Message",
71-
{Message_mark, RUBY_DEFAULT_FREE, NULL},
75+
{Message_mark, RUBY_DEFAULT_FREE, Message_memsize},
7276
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
7377
};
7478

ruby/ext/google/protobuf_c/protobuf.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,22 @@ static void Arena_free(void *data) {
187187
xfree(arena);
188188
}
189189

190+
static size_t Arena_memsize(const void *data) {
191+
const Arena *arena = data;
192+
size_t memsize = upb_Arena_SpaceAllocated(arena->arena);
193+
if (arena->arena->refcount > 1) {
194+
// If other arena were fused we attribute an equal
195+
// share of memory usage to each one.
196+
memsize /= arena->arena->refcount;
197+
}
198+
return memsize + sizeof(Arena);
199+
}
200+
190201
static VALUE cArena;
191202

192203
const rb_data_type_t Arena_type = {
193204
"Google::Protobuf::Internal::Arena",
194-
{Arena_mark, Arena_free, NULL},
205+
{Arena_mark, Arena_free, Arena_memsize},
195206
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
196207
};
197208

ruby/tests/memory_test.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/ruby
2+
#
3+
# generated_code.rb is in the same directory as this test.
4+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
5+
6+
require 'test/unit'
7+
require 'objspace'
8+
require 'test_import_pb'
9+
10+
class MemoryTest < Test::Unit::TestCase
11+
# 40 byte is the default object size. But the real size is dependent on many things
12+
# such as arch etc, so there's no point trying to assert the exact return value here.
13+
# We merely assert that we return something other than the default.
14+
def test_objspace_memsize_of_arena
15+
assert_operator 40, :<, ObjectSpace.memsize_of(Google::Protobuf::Internal::Arena.new)
16+
end
17+
18+
def test_objspace_memsize_of_message
19+
assert_operator 40, :<, ObjectSpace.memsize_of(FooBar::TestImportedMessage.new)
20+
end
21+
22+
def test_objspace_memsize_of_map
23+
assert_operator 40, :<, ObjectSpace.memsize_of(Google::Protobuf::Map.new(:string, :int32))
24+
end
25+
end

0 commit comments

Comments
 (0)