Issue #16291 has been updated by mame (Yusuke Endoh).

Target version set to 2.8
Assignee set to nobu (Nobuyoshi Nakada)
Tracker changed from Misc to Feature

This ticket was discussed at the previous dev meeting, and @nobu will revie=
w the patch and merge it if okay.

----------------------------------------
Feature #16291: Introduce support for resize in rb_ary_freeze and prefer in=
ternal use of rb_ary_freeze and rb_str_freeze for String and Array types
https://bugs.ruby-lang.org/issues/16291#change-83407

* Author: methodmissing (Lourens Naud=E9)
* Status: Open
* Priority: Normal
* Assignee: nobu (Nobuyoshi Nakada)
* Target version: 2.8
----------------------------------------
References Github PR https://github.com/ruby/ruby/pull/2640

### Why?

While working on https://github.com/ruby/ruby/pull/2037#issuecomment-548633=
141 I also looked at the `rb_ary_freeze` helper to determine if the same op=
timization of shrinking capacity can be applied there as well.

Further investigation revealed that `rb_str_freeze` attempts to resize / sh=
rink strings on freeze, but we currently don't do the same for arrays despi=
te API for it being exposed.

The gist of the change:

* Let `rb_ary_freeze` also attempt to right size an array before freezing it
* Replaced internal use of `rb_obj_freeze` and `OBJ_FREEZE` of callsites th=
at pass a String or Array type in with `rb_ary_freeze` and `rb_str_freeze` =
specifically.

### Results

Saves about 3MB of Array and String specific heap footprints on a redmine p=
roduction env boot on Rails 6 (custom local upgrade - it does not officiall=
y support it yet):

```
Loading production environment (Rails 6.1.0.alpha)
irb(main):001:0> RUBY_DESCRIPTION
=3D> "ruby 2.7.0dev (2019-11-02T06:32:49Z master 772b0613c5) [x86_64-linux]"
irb(main):002:0> require 'objspace'
=3D> true
irb(main):003:0> GC.start
=3D> nil
irb(main):004:0> ObjectSpace.each_object(Array).sum {|o| ObjectSpace.memsiz=
e_of(o) }
=3D> 4451200
irb(main):005:0> ObjectSpace.each_object(String).sum {|o| ObjectSpace.memsi=
ze_of(o) }
=3D> 8608472
irb(main):006:0> exit
```

```
Loading production environment (Rails 6.1.0.alpha)
irb(main):001:0> RUBY_DESCRIPTION
=3D> "ruby 2.7.0dev (2019-11-02T16:52:34Z obj-freeze-specifi.. 3bc4048899) =
[x86_64-linux]"
irb(main):002:0> require 'objspace'
=3D> true
irb(main):003:0> GC.start
=3D> nil
irb(main):004:0> ObjectSpace.each_object(Array).sum {|o| ObjectSpace.memsiz=
e_of(o) }
=3D> 3233432
irb(main):005:0> ObjectSpace.each_object(String).sum {|o| ObjectSpace.memsi=
ze_of(o) }
=3D> 6748422
```

irb - the best calculator ...

```
irb(main):002:0> (4451200 - 3233432) / 1024
=3D> 1189
irb(main):003:0> (8608472 - 6748422) / 1024
=3D> 1816
```

### Open questions

* Would it make sense to let `rb_obj_freeze` switch on object type instead =
and apply this optimization without "polluting" internals with custom calls=
ite changes? Native extensions can then benefit from the resize feature too.
* HOWEVER: Discovered in testing that `rb_str_freeze` can fail asserts in `=
rb_str_tmp_frozen_release` when sprinkled too generously especially in `io.=
c`. And other issues may lurk too, thus incorporating the resizing in `rb_o=
bj_freeze` won't work.  See https://github.com/ruby/ruby/pull/2640#issuecom=
ment-549119359

I think it could also make sense to split the PR in 2:

* One changeset for `rb_ary_freeze` attempting to resize Arrays on freeze, =
special case internal `rb_obj_freeze` of Arrays to prefer the new API
* Apply `rb_str_resize` at internal call sites where `rb_obj_freeze` is use=
d with String types

Thoughts?



-- =

https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=3Dunsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>