Skip to content

variables in closure iterators loop are not correctly unassigned #19193

@Menduist

Description

@Menduist

Example

iterator test(): int {.closure.} =
  for i in 0..<1000000:
    var heavy: seq[int]
    heavy = newSeq[int](10000)
    yield heavy.len

GC_disableMarkAndSweep()

for i in test():
  discard

will use a lot of memory, because the lines:

var heavy: seq[int]
heavy = newSeq[int](10000)

will generate:

(*colonenvP_).heavy2 = (tySequence__qwqHTkRvwhrRyENtudHQ7g*)0;
asgnRef((void**) (&(*colonenvP_).heavy2), newSeq__eA9b5cYyFZe7gRm4F9aRTKlA(((NI) 10000)));

which erases the last reference before calling asgnRef.

Assigning directly avoids this issue:
var heavy = newSeq[int](10000)
Because the heavy2 = 0 line is not generated, and asgnRef will call decRef on the last value.

Possible Solution

It seems that in regular procs, the var line will be translated to:

asgnRef((void**) (&fut__JYhQvJxHhtC8fq7FzTRUVQ), NIM_NIL);
asgnRef((void**) (&fut__JYhQvJxHhtC8fq7FzTRUVQ), testInner__bhBT5he32hyARROogQacKg());

Since we assign to NIL instead of setting to 0 manually, the reference count is correctly updated

Additional Information

Happens both on 1.2.6 & devel.
Obviously, the mark & sweep will catch that, but as part of optimizing ram consumption in nimbus, we're trying to rely on it as little as possible

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions