这两种垃圾中的一种收集方式不同,还是一样?
array_of_strings.each do |str|
MailerClass.some_template(str).deliver_later
end
VS
array_of_strings.map do |str|
MailerClass.some_template(str).deliver_later
end
我已经格式化了邮件对象和任务队列的问题,因为这是我最近一直在处理的问题,但是如果这会使答案过于复杂,那么我可以将其改为更通用。
背景,相关:
我认为
.map
会返回一个指向每个对象的对象 已创建的对象,而.each
则不会。 [这似乎是 不是这样的]我有一台工作机器泄漏内存直到崩溃 - 所有 发生在这个伪代码示例的一个事件中 中央行动。当我将其从
.each
更改为.map
时,则将其更改为type CoreOperators<T> = { map: <R>(f: (item: T) => R) => Observable<R>; scan: <R>(f: (prev: R, next: T) => R) => Observable<R>; }; type Observable<T> = CoreOperators<T> & { observableSpecificMethod: (f: Function) => Observable<T> };
内存泄漏已停止,但我不知道GC是如何发生的 关于这些方法。
答案 0 :(得分:1)
由于map返回使用array_of_strings的每个成员计算块的结果的数组,因此至少会有一个额外的对象被收集。
答案 1 :(得分:1)
根据您使用的确切Ruby实现,Enumerable#map
的实现可以用Ruby,Smalltalk,RPython,ECMAScript,C#,Java,Go,Objective-C,C ++,C或任意数量的其他语言,但其工作方式总是如下:
module Enumerable
def map
return enum_for(__method__) unless block_given?
[].tap {|result| each {|el| result << yield el }}
end
end
map
必须调用each
,根本无法进行迭代。因此,它将分配完全相同的对象,each
将分配加上附加结果Array
,即恰好比each
多一个对象。
实际上,许多Ruby实现使用Enumerable#map
覆盖Array#map
,这比通用Enumerable
版本更有效。它们通常直接遍历Array
元素而不调用each
,有点像这样:
class Array
def map
return enum_for(__method__) unless block_given?
result = []
i = -1
while i += 1 <= size
result << yield @__entries__[i]
end
end
end
这比通用Enumerable#map
更有效,因为它使用了有关如何迭代Array
的特殊知识,以避免方法调用开销each
。但是请注意,each
将以完全相同的方式实现,除非实现者非常愚蠢,因此最终结果是相同的:map
仍然会分配超过{{1}的一个对象它只是保存一个方法调用。
请注意,由于您忽略了each
的返回值,因此额外对象立即有资格进行垃圾回收。但是,在此之前,它保存对map
方法返回的所有对象的引用,无论它们是什么。
因此,两段代码之间的差异是:
deliver_later
,each
的返回值将被忽略,并有资格立即进行垃圾回收deliver_later
一起,分配了一个额外的map
,它保留了对块内所有Array
调用的返回值的引用,从而使这些对象保持活动状态,直到在对deliver_later
的调用返回之后,map
及其引用的所有对象将同时符合垃圾回收的条件