Первичный ответ, что в вашем втором блоке кода, ни один из затворов (closure1
или someMethod
) выживает возвращение outer
(ничего вне outer
относится к ним), и поэтому там не осталось ничего, что относится к контексту, где они были созданы, и этот контекст можно очистить. Однако во втором блоке кода someMethod
выживает при возврате, как часть объекта, который вы назначаете aThing
, и поэтому контекст не может быть GC'd.
Давайте проследим, что происходит с вашим первым блоком:
После первого исполнения outer
, мы (не обращая внимания на кучу деталей):
+-------------+
aThing----->| (object #1) |
+-------------+
| str: ... | +--------------------+
| someMethod |---->| (context #1) |
+-------------+ +--------------------+
| something: null |
| closure1: function |
+--------------------+
после выполнения на второго:
+-------------+
aThing----->| (object #2) |
+-------------+
| str: ... | +--------------------+
| someMethod |---->| (context #2) |
+-------------+ +--------------------+ +-------------+
| something |---->| (object #1) |
| closure1: function | +-------------+
+--------------------+ | str: ... | +--------------------+
| someMethod |---->| (context #1) |
+-------------+ +--------------------+
| something: null |
| closure1: function |
+--------------------+
после третий исполнитель на:
+-------------+
aThing----->| (object #3) |
+-------------+
| str: ... | +--------------------+
| someMethod |---->| (context #3) |
+-------------+ +--------------------+ +-------------+
| something |---->| (object #2) |
| closure1: function | +-------------+
+--------------------+ | str: ... | +--------------------+
| someMethod |---->| (context #2) |
+-------------+ +--------------------+ +-------------+
| something |---->| (object #1) |
| closure1: function | +-------------+
+--------------------+ | str: ... | +--------------------+
| someMethod |---->| (context #1) |
+-------------+ +--------------------+
| something: null |
| closure1: function |
+--------------------+
Вы можете видеть, куда это направляется.
Поскольку второй блок никогда не сохраняет ссылку на closure1
или someMethod
, ни один из них не сохраняет контекст в памяти.
Я немного удивлен тем, что V8 (двигатель JavaScript в Chrome) не оптимизирует эту утечку далеко, поскольку сохраняется только someMethod
и someMethod
фактически не используют something
или closure1
(или eval
или new Function
или debugger
), так хотя теоретически он имеет ссылки на них через контекст, статический анализ показал бы, что они фактически не могут использоваться и поэтому могут быть отброшены. Но оптимизация закрытия на самом деле легко беспокоить, я думаю, что что-то в ней беспокоит.
1. Избегайте менять более одного предмета. Несмотря на то, что это почти бесполезно, не меняйте порядок первых двух утверждений в 'outer' **, а также ** делайте что-то еще. Выяснение этих факторов требует создания ** одного ** изменения во время и устранения нерелевантности. 2. При обращении за помощью, пожалуйста, уделите время, чтобы сделать код подданным читаемым и последовательным. Я исправил №2 для вас. –
OP, интересно @ T.J.Crowder [пишет о сборке мусора здесь] (http://stackoverflow.com/questions/4324133/how-does-garbage-collection-work-in-javascript), который может немного помочь вам. – Andy