我只是注意到,如果您不清除或替换字符串,则内存使用不会减少。
文件x.rb:
#!/usr/bin/ruby -w
raise(RuntimeError, 'A GNU/Linux or an Android system is needed') unless /linux/ === RUBY_PLATFORM.downcase
require 'objspace'
STDOUT.sync = true
GC.start(full_mark: true, immediate_sweep: true)
define_method(:show) { "System Memory Usage: #{::IO.readlines('/proc/meminfo').then { |x| [x[0], x[2]] }
.map { |x| x.split[1].to_f }.reduce(:-)./(1024).round(3)} MiB "\
"| Available: #{::IO.readlines('/proc/meminfo')[2].split[1].to_f./(1024).round(3)} MiB" }
define_method(:memsize) { |obj| ObjectSpace.memsize_of(obj).to_s.reverse.gsub(/\d{1,3}/).to_a.join(',').reverse << ' Bytes'}
Run Code Online (Sandbox Code Playgroud)
文件y.rb:
#!/usr/bin/ruby -w
fail(NoMemoryError, 'Not enough available memory') if ::IO.readlines('/proc/meminfo')[2].split[1].to_i < 600_000
require_relative(File.join(__dir__, 'x'))
puts show
a = '0' * 500_000_000
puts "Memory used by a: #{memsize(a)}"
puts show
a = ''
puts "Memory used by a: #{memsize(a)}"
puts show
Run Code Online (Sandbox Code Playgroud)
文件z.rb:
#!/usr/bin/ruby -w
fail(NoMemoryError, 'Not enough available memory') if ::IO.readlines('/proc/meminfo')[2].split[1].to_i < 600_000
require_relative(File.join(__dir__, 'x'))
puts show
a = '0' * 500_000_000
puts "Memory used by a: #{memsize(a)}"
puts show
a.clear
puts "Memory used by a: #{memsize(a)}"
puts show
Run Code Online (Sandbox Code Playgroud)
y.rb的输出:
System Memory Usage: 2316.289 MiB | Available: 1445.23 MiB
Memory used by a: 500,000,041 Bytes
System Memory Usage: 2795.504 MiB | Available: 966.016 MiB
Memory used by a: 40 Bytes
System Memory Usage: 2795.504 MiB | Available: 966.016 MiB
Run Code Online (Sandbox Code Playgroud)
z.rb的输出:
System Memory Usage: 2301.359 MiB | Available: 1460.16 MiB
Memory used by a: 500,000,041 Bytes
System Memory Usage: 2780.098 MiB | Available: 981.422 MiB
Memory used by a: 40 Bytes
System Memory Usage: 2303.387 MiB | Available: 1458.133 MiB
Run Code Online (Sandbox Code Playgroud)
现在,尽管将a分配给空字符串,问题仍然存在,运行文件y.rb会占用大约500兆的内存,直到程序退出。
z.rb清除字符串。
这也不会清除内存:
a[0..-1] = ''
Run Code Online (Sandbox Code Playgroud)
请注意,我的程序和gnome-system-monitor都同意使用系统RAM。
为什么会这样呢?当赋值运算符不起作用时,清除如何工作?
a = ''并a.clear做些微妙的事情。
a = ''创建一个新String对象并将其分配给a。旧String对象仍在内存中浮动,等待被垃圾回收。
2.4.4 :010 > a = 'foo'
=> "foo"
2.4.4 :011 > a.object_id
=> 70311739468740
2.4.4 :012 > a = ''
=> ""
2.4.4 :013 > a.object_id
=> 70311748786840
Run Code Online (Sandbox Code Playgroud)
注意不同的对象ID。
a.clear清除现有String对象。
2.4.4 :016 > a = 'foo'
=> "foo"
2.4.4 :017 > a.object_id
=> 70311748749240
2.4.4 :018 > a.clear
=> ""
2.4.4 :019 > a.object_id
=> 70311748749240
Run Code Online (Sandbox Code Playgroud)
注意对象ID是相同的。
专门clear调用str_discard会立即释放分配给的内存String。
static inline void
str_discard(VALUE str)
{
str_modifiable(str);
if (!STR_EMBED_P(str) && !FL_TEST(str, STR_SHARED|STR_NOFREE)) {
ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
RSTRING(str)->as.heap.ptr = 0;
RSTRING(str)->as.heap.len = 0;
}
}
Run Code Online (Sandbox Code Playgroud)
另一种看到差异的方式...
2.4.4 :026 > a = 'foo'
=> "foo"
2.4.4 :027 > b = a
=> "foo"
2.4.4 :028 > a.object_id
=> 70311748602540
2.4.4 :029 > b.object_id
=> 70311748602540
Run Code Online (Sandbox Code Playgroud)
a并b指向同一基础对象。
2.4.4 :030 > a = ''
=> ""
2.4.4 :031 > b
=> "foo"
2.4.4 :032 > a.object_id
=> 70311748541360
2.4.4 :033 > b.object_id
=> 70311748602540
Run Code Online (Sandbox Code Playgroud)
在之后a = '',a指向一个新对象,而b指向原始对象。这说明了为什么a = ''无法立即释放内存,而其他可能引用了原始内存String。
如果我们再次设置...
2.4.4 :034 > a = 'foo'
=> "foo"
2.4.4 :035 > b = a
=> "foo"
2.4.4 :036 > a.object_id
=> 70311748490260
2.4.4 :037 > b.object_id
=> 70311748490260
Run Code Online (Sandbox Code Playgroud)
但是这次使用a.clear...
2.4.4 :038 > a.clear
=> ""
2.4.4 :039 > b
=> ""
2.4.4 :040 > a.object_id
=> 70311748490260
2.4.4 :041 > b.object_id
=> 70311748490260
Run Code Online (Sandbox Code Playgroud)
a并且b仍然都引用同一个对象。