Feature #5875

Couple of tiny changes to string

Added by Yura Sokolov about 5 years ago. Updated about 5 years ago.

Target version:


  • change capacity increment from (capa + 1) * 2 to capa * 2 + 1 previous increment formula leads to inconvenient allocation patterns: 25bytes, 51bytes, etc new formula leads to more comfortable allocation pattern: 24b, 48b, 96b
  • change STR_BUF_MIN_SIZE from 128 to 79 128 leads to allocation of 129 bytes, which is very uncomfortable for allocators and unnecessary large. (during Redmine startup this method is called about 3000000 times with capa < 128)

Associated revisions

Revision 55686
Added by normal 7 months ago

string.c: reduce malloc overhead for default buffer size

  • string.c (STR_BUF_MIN_SIZE): reduce from 128 to 127 [Feature #12025]
  • string.c (rb_str_buf_new): adjust for above reduction

From Jeremy Evans

This changes the minimum buffer size for string buffers from 128 to
127. The underlying C buffer is always 1 more than the ruby buffer,
so this changes the actual amount of memory used for the minimum
string buffer from 129 to 128. This makes it much easier on the
malloc implementation, as evidenced by the following code (note that
time -l is used here, but Linux systems may need time -v).

$ cat bench_mem.rb
i = ARGV.first.to_i{" " * i}
$ /usr/bin/time -l ruby bench_mem.rb 128
3.10 real 2.19 user 0.46 sys
289080 maximum resident set size
72673 minor page faults
13 block output operations
29 voluntary context switches
$ /usr/bin/time -l ruby bench_mem.rb 127
2.64 real 2.09 user 0.27 sys
162720 maximum resident set size
40966 minor page faults
2 block output operations
4 voluntary context switches

To try to ensure a power-of-2 growth, when a ruby string capacity
needs to be increased, after doubling the capacity, add one. This
ensures the ruby capacity will be odd, which means actual amount
of memory used will be even, which is probably better than the
current case of the ruby capacity being even and the actual amount
of memory used being odd.

A very similar patch was proposed 4 years ago in feature #5875. It
ended up being rejected, because no performance increase was shown.
One reason for that is that ruby does not use STR_BUF_MIN_SIZE
unless rb_str_buf_new is called, and that previously did not have
a ruby API, only a C API, so unless you were using a C extension
that called it, there would be no performance increase.

With the recently proposed feature #12024, String.buffer is added,
which is a ruby API for creating string buffers. Using
String.buffer(100) wastes much less memory with this patch, as the
malloc implementation can more easily deal with the power-of-2
sized memory usage. As measured above, memory usage is 44% less,
and performance is 17% better.


#1 [ruby-core:42059] Updated by Motohiro KOSAKI about 5 years ago

  • Status changed from Open to Closed

Closed by reporter's request.

Also available in: Atom PDF