我在处理File.realpath()时遇到了麻烦,似乎没有收集到乱码。在我看来,这看起来像是内存泄漏,尽管我无法想象这样的事情对于核心库方法实际上是正确的。
考虑以下代码:
def string_test(string)
puts string
end
GC.start
report = MemoryProfiler.report do
s = './foo.txt'.freeze
string_test(s)
s = nil
GC.start
end
report.pretty_print
这会产生(以及其他详细输出):
Total allocated: 0 bytes (0 objects)
Total retained: 0 bytes (0 objects)
到目前为止,调用string_test()方法似乎没有剩余内存使用情况。但是,如果我更改方法来解析相对路径,如下所示:
def string_test(string)
puts File.realpath(string)
end
我从MemoryProfiler得到以下输出:
Total allocated: 128 bytes (2 objects)
Total retained: 88 bytes (1 objects)
.
.
.
Retained String Report
-----------------------------------
1 "/home/asdfjk/tmp/foo.txt"
1 t:28
foo.txt是指向实际文件的符号链接。我不知道这是否相关。似乎File.realpath()留下了字符串的副本。聚合超过数十万个文件,它将占用大量内存。谁能帮助我了解这里发生的事情以及可能的解决方法?
另一个有趣的窍门是,在第一个示例(不泄漏的示例)中,必须冻结字符串s,否则结果与包括对File.realpath()的调用的版本相同。
答案 0 :(得分:0)
我使用ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin18]
和文件./foo.txt
(也是符号链接)./foo
进行了测试。
如果我们将您的示例缩减到最低限度,那么答案是否定的,File.realpath
中没有内存泄漏:
require 'memory_profiler'
MemoryProfiler.report { puts File.realpath('./foo.txt') }.pretty_print
<snip>
Retained String Report
-----------------------------------
您看到的问题归结于您对GC.start
,.freeze
的调用以及MemoryProfiler
在代码块中测量这些东西的方式的组合。
关于puts string
和puts File.realpath(string)
的行为为何不同,puts string
读取string
的值并将其打印到控制台; puts File.realpath(string)
创建一个新的String
对象,然后将其打印到控制台。