-
Notifications
You must be signed in to change notification settings - Fork 21
don't generate unneeded references to outer objects in inner classes #1419
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
Comments
Imported From: https://issues.scala-lang.org/browse/SI-1419?orig=1 |
@stepancheg said: |
@stepancheg said: |
@eengbrec said: |
@stepancheg said: val m = new WeakHashMap[A, Something]
class A {
class X
def f = new X
}
def g = {
val a = new A
m += (a, someValue)
a.f
} someValue will be garbage collected if X has no reference to outer class. |
@stepancheg said: val m = new WeakHashMap[A, Something]
class A {
class X
def f = new X
}
def g = {
val a = new A
m += (a, someValue)
a.f
} someValue will be garbage collected if X has no reference to outer class. |
@eengbrec said: That being said, isn't the point of a WeakHashMap to allow objects to be GC'd? |
@DRMacIver said: |
Oscar Boykin (oscar) said: It makes generic serialization libraries (like Kryo, which we use) very difficult because we have to see if the outer$ parameter is really accessed or not (something Spark works around with ASM which is obviously an awful hack). We see this issue on scala 2.9.2. Our main work around now is to tell our users "don't do that". But it's difficult to explain to non-experts why it should matter. |
@adriaanm said: |
@adriaanm said: |
Daniel Vizzini (dvizzini) said (edited on Jul 3, 2014 5:44:39 PM UTC): https://groups.google.com/forum/#!topic/cascading-user/-ChrHc3g1vo It is responsible for numerous job failures, which often do not show up until a job has been run for more than an hour. Any work on this would greatly improve an increasingly popular open-source framework. |
@nilskp said (edited on Jun 24, 2015 7:08:40 PM UTC): More specifically, is there any reason the outer instance is needed at runtime (if not referenced, of course)? |
@adriaanm said (edited on Jun 24, 2015 7:17:44 PM UTC): Is it an option to simply not nest this class? PS: there's an undocumented "feature" that final nested classes don't receive outer pointers (unless required): ➜ ~ scalac -Xprint:cleanup /tmp/outer.scala
[[syntax trees at end of cleanup]] // outer.scala
package <empty> {
class C extends Object {
def <init>(): C = {
C.super.<init>();
()
}
};
final class C$FinalNested extends Object {
def <init>($outer: C): C$FinalNested = {
C$FinalNested.super.<init>();
()
}
};
class C$Nested extends Object {
<synthetic> <paramaccessor> <artifact> protected val $outer: C = _;
<synthetic> <stable> <artifact> def $outer(): C = C$Nested.this.$outer;
def <init>($outer: C): C$Nested = {
if ($outer.eq(null))
throw null
else
C$Nested.this.$outer = $outer;
C$Nested.super.<init>();
()
}
}
} for class C {
final class FinalNested
class Nested
} |
@adriaanm said: class D {
val c1 = new C
val c2 = new C
val fn1 = new c1.FinalNested
val fn2 = new c2.FinalNested
val n1 = new c1.FinalNested
val n2 = new c2.FinalNested
(n1: Any) match { case x: c2.FinalNested => x}
(fn1: Any) match { case x: c2.Nested => x}
} |
@adriaanm said: - if (x1.$isInstanceOf[C$FinalNested]().&&(true))
+ if (x1.$isInstanceOf[C$Nested]().&&((x1.$asInstanceOf[C$Nested](): C$Nested).$outer().eq(D.this.c2()))) |
@nilskp said: Although I'm happy to use |
@adriaanm said: |
@nilskp said: I'm beginning to wish Scala's default would be final, with some keyword to allow extension, perhaps BTW, given the explanation, is there any hope this issue having any other resolution that "Won't Fix", i.e. why it's still open? |
@adriaanm said: |
@adriaanm said (edited on Jun 26, 2015 12:28:13 AM UTC): |
@nilskp said: |
@adriaanm said: |
@adriaanm said: |
@adriaanm said (edited on Jun 26, 2015 3:27:06 PM UTC): |
@adriaanm said: |
@nilskp said: @Test
def methodLift {
def isPrime(c: Int) = BigInt(c).isProbablePrime(1)
assertNoOuter(isPrime)
}
@Test
def asFunction {
val isPrime = (c: Int) => BigInt(c).isProbablePrime(1)
assertNoOuter(isPrime)
}
private def assertNoOuter(f: Int => Boolean) {
assertFalse(f.getClass.getDeclaredFields.exists(_.getType == this.getClass))
}
|
Oscar Boykin (oscar) said: |
@adriaanm said: |
Oscar Boykin (oscar) said: |
@adriaanm said: |
@nilskp said: |
Currently (change set 16246 of trunk) named inner classes always contain a reference to their enclosing object, regardless of whether it is use or not. This is similar to the old behavior of anonymous inner classes as demonstrated in https://lampsvn.epfl.ch/trac/scala/ticket/854 . I think named inner classes should not retain a reference to the enclosing object if it is not required so that subtle memory leaks can be avoided.
The text was updated successfully, but these errors were encountered: