diff options
author | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2021-08-29 16:47:26 +0900 |
---|---|---|
committer | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2021-08-29 17:18:58 +0900 |
commit | a615885f1e87f4bfbc5398b060fd3a64d5de8c4a (patch) | |
tree | c0045c949a33c1e661744e8d8e9f70deb1d36629 | |
parent | 265a725830a487b846bc32f70346f6438c95a7e9 (diff) |
Free previously used tables [Bug #18134]
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/4788
-rw-r--r-- | hash.c | 22 | ||||
-rw-r--r-- | test/ruby/test_hash.rb | 9 |
2 files changed, 16 insertions, 15 deletions
@@ -2951,25 +2951,17 @@ rb_hash_replace(VALUE hash, VALUE hash2) COPY_DEFAULT(hash, hash2); if (RHASH_AR_TABLE_P(hash)) { - if (RHASH_AR_TABLE_P(hash2)) { - ar_clear(hash); - } - else { - ar_free_and_clear_table(hash); - RHASH_ST_TABLE_SET(hash, st_init_table_with_size(RHASH_TYPE(hash2), RHASH_SIZE(hash2))); - } + ar_free_and_clear_table(hash); } else { - if (RHASH_AR_TABLE_P(hash2)) { - st_free_table(RHASH_ST_TABLE(hash)); - RHASH_ST_CLEAR(hash); - } - else { - st_clear(RHASH_ST_TABLE(hash)); - RHASH_TBL_RAW(hash)->type = RHASH_ST_TABLE(hash2)->type; - } + st_free_table(RHASH_ST_TABLE(hash)); + RHASH_ST_CLEAR(hash); } hash_copy(hash, hash2); + if (RHASH_EMPTY_P(hash2) && RHASH_ST_TABLE_P(hash2)) { + /* ident hash */ + RHASH_ST_TABLE_SET(hash, st_init_table_with_size(RHASH_TYPE(hash2), 0)); + } rb_gc_writebarrier_remember(hash); diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index ac0d1dfce3..f79879c20a 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -1278,6 +1278,15 @@ class TestHash < Test::Unit::TestCase assert_raise(FrozenError) { h2.replace(42) } end + def test_replace_memory_leak + assert_no_memory_leak([], "#{<<-"begin;"}", "#{<<-'end;'}") + h = ("aa".."zz").each_with_index.to_h + 10_000.times {h.dup} + begin; + 500_000.times {h.dup.replace(h)} + end; + end + def test_size2 assert_equal(0, @cls[].size) end |