我刚刚注意到,如果您既不清除也不替换字符串,内存使用量不会减少。
文件 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'}
文件 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
文件 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
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
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
尽管将 a 分配给一个空字符串,但现在的问题是,运行文件 y.rb 会使用大约 500 兆内存,直到程序退出。
z.rb 清除字符串。
这也不会清除内存:
a[0..-1] = ''
请注意,我的程序和 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
注意不同的对象 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
请注意对象 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;
}
}
另一种查看差异的方法...
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
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
在 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
但是这次使用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
a
和 b
仍然指代同一个对象。
关于ruby - 为什么重新分配字符串不会减少 Ruby 中的内存使用量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56743116/