Skip to content

By-name params used only in a lazy field should be cleared to prevent leaks #1692

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Blaisorblade opened this issue Nov 10, 2016 · 3 comments
Assignees

Comments

@Blaisorblade
Copy link
Contributor

Noticed in #1691 — scalac, but not dotty (as pointed out by @smarter), compiles the following so the initializer for byLazyValMsg clears byNameMsg. This is not just an optimization, but is needed for correctness to prevent memory leaks:

class TestByNameLazy(byNameMsg: => String) {
  lazy val byLazyValMsg = byNameMsg
}

Resulting code with Scalac (as decompiled with jad)—note byName = null;:

public class TestByNameLazy
{

    private String byLVal$lzycompute()
    {
        synchronized(this)
        {
            if(!bitmap$0)
            {
                byLVal = (String)byName.apply();
                bitmap$0 = true;
            }
            BoxedUnit _tmp = BoxedUnit.UNIT;
        }
        byName = null;
        return byLVal;
    }

    public String byLVal()
    {
        return bitmap$0 ? byLVal : byLVal$lzycompute();
    }

    public TestByNameLazy(Function0 byName)
    {
        this.byName = byName;
        super();
    }

    private final Function0 byName;
    private String byLVal;
    private volatile boolean bitmap$0;
}

Is this documented anywhere?

Maybe but not to my knowledge; I've seen similar patterns often enough and Dragos described this in scala/scala#922 as:

Less known fact: lazy values null-out their dependent values is they're accessed only from
their initializer.

I found that PR by searching JIRA https://issues.scala-lang.org/browse/SI-6092 (which is not about this "feature" missing altogether, just about a bug with it).

@odersky
Copy link
Contributor

odersky commented Nov 10, 2016

@DarkDimius Let's discuss how this can be best achieved. Looks not easy to me.

@DarkDimius
Copy link
Contributor

DarkDimius commented Nov 25, 2016

This can be achived by having a pass before lazy vals that marks that private val byNameMsg is only used inside this lazy val and making lazyVals null out the private function field in such cases.

@allanrenucci
Copy link
Contributor

Needed to make collections-strawman tests pass

allanrenucci added a commit to dotty-staging/dotty that referenced this issue Apr 10, 2018
Private fields that are only used during lzyy val initialization can be
assigned null once the lazy val is initialized. This is not just an
optimization, but is needed for correctness to prevent memory leaks.
allanrenucci added a commit to dotty-staging/dotty that referenced this issue Apr 10, 2018
Private fields that are only used during lzyy val initialization can be
assigned null once the lazy val is initialized. This is not just an
optimization, but is needed for correctness to prevent memory leaks.
allanrenucci added a commit to dotty-staging/dotty that referenced this issue Apr 11, 2018
Private fields that are only used during lzyy val initialization can be
assigned null once the lazy val is initialized. This is not just an
optimization, but is needed for correctness to prevent memory leaks.
allanrenucci added a commit to dotty-staging/dotty that referenced this issue Apr 11, 2018
Private fields that are only used during lazy val initialization can be
assigned null once the lazy val is initialized. This is not just an
optimization, but is needed for correctness to prevent memory leaks.
allanrenucci added a commit to dotty-staging/dotty that referenced this issue Apr 11, 2018
Private fields that are only used during lazy val initialization can be
assigned null once the lazy val is initialized. This is not just an
optimization, but is needed for correctness to prevent memory leaks.
allanrenucci added a commit to dotty-staging/dotty that referenced this issue Apr 12, 2018
Private fields that are only used during lazy val initialization can be
assigned null once the lazy val is initialized. This is not just an
optimization, but is needed for correctness to prevent memory leaks.
allanrenucci added a commit to dotty-staging/dotty that referenced this issue Apr 30, 2018
Private fields that are only used during lazy val initialization can be
assigned null once the lazy val is initialized. This is not just an
optimization, but is needed for correctness to prevent memory leaks.
allanrenucci added a commit to dotty-staging/dotty that referenced this issue May 1, 2018
Private fields that are only used during lazy val initialization can be
assigned null once the lazy val is initialized. This is not just an
optimization, but is needed for correctness to prevent memory leaks.
allanrenucci added a commit to dotty-staging/dotty that referenced this issue May 1, 2018
Private fields that are only used during lazy val initialization can be
assigned null once the lazy val is initialized. This is not just an
optimization, but is needed for correctness to prevent memory leaks.
allanrenucci added a commit to dotty-staging/dotty that referenced this issue May 9, 2018
Private fields that are only used during lazy val initialization can be
assigned null once the lazy val is initialized. This is not just an
optimization, but is needed for correctness to prevent memory leaks.
allanrenucci added a commit that referenced this issue May 9, 2018
Fix #1692: Null out fields after use in lazy initialization
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants