From: jrafanie@... Date: 2018-01-26T17:19:39+00:00 Subject: [ruby-core:85134] [Ruby trunk Bug#14372] Memory leak in require with Pathnames in the $LOAD_PATH in 2.3/2.4 Issue #14372 has been updated by jrafanie (Joe Rafaniello). Because `Rails.root` is a `Pathname`, it's a fairly common for developers to use Rails.root.join("lib") or something similar in their autoload_paths or eager_load_paths, both of which end up in the $LOAD_PATH and lead to a leak on each call to require. This memory has been found in various open source projects and workarounds provided (convert `Pathname` objects destined for the `$LOAD_PATH` to strings): https://github.com/lobsters/lobsters/pull/449 https://github.com/opf/openproject/pull/6148 https://github.com/errbit/errbit/pull/1257 https://github.com/ManageIQ/manageiq/pull/16837 https://github.com/ManageIQ/manageiq-api/pull/288 https://github.com/ManageIQ/manageiq-automation_engine/pull/146 https://github.com/ManageIQ/manageiq-ui-classic/pull/3266 https://github.com/ManageIQ/manageiq-graphql/pull/34 ---------------------------------------- Bug #14372: Memory leak in require with Pathnames in the $LOAD_PATH in 2.3/2.4 https://bugs.ruby-lang.org/issues/14372#change-69859 * Author: jrafanie (Joe Rafaniello) * Status: Open * Priority: Normal * Assignee: * Target version: * ruby -v: ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin16] * Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN ---------------------------------------- There is a memory leak that we have found on ruby 2.3.6 and 2.4.3 that happens on Mac OSX and Linux. Ruby 2.2.6 and 2.5.0 do not leak. We have not tested other platforms. If `$LOAD_PATH` contains one or more Pathname objects, `require` without a fully qualified path, such as `require 'ostruct'`, will leak if you do this require many times. For example, the following script will leak very quickly on ruby 2.3.6 and 2.4.3: ~~~ruby require 'pathname' puts Process.pid $LOAD_PATH.unshift(Pathname.new(__dir__)) dot = "." filename = "ostruct" 1000.times { 1000.times { require filename }; print dot; GC.start; } ~~~ From what we can understand, it appears that `rb_require_internal` calls `rb_feature_p` which ultimately calls `rb_file_expand_path_fast` and resizes a string. It doesn't seem like the memory is ever freed either in c or the garbage collector. This happens many times, perhaps because Pathname objects, unlike Strings, aren't cached in loaded features so they get expanded each time. See below: https://github.com/ruby/ruby/blob/v2_3_6/load.c#L43-L47 We can workaround this problem by converting Pathname objects in `$LOAD_PATH` to Strings, but this leak should be fixed since this it's common to use Pathname objects in `$LOAD_PATH`. We used the instruments tool on OSX to show one such leak and the callstack, see attached image. ---Files-------------------------------- Instruments2 2018-01-18 11-43-32.png (181 KB) -- https://bugs.ruby-lang.org/ Unsubscribe: