Fix lazy {} memory leak regression caused by #3862
This commit is contained in:
committed by
GitHub
parent
33f9f9b917
commit
53022fac12
@@ -1040,6 +1040,10 @@ standaloneTest("lazy2") {
|
||||
source = "runtime/workers/lazy2.kt"
|
||||
}
|
||||
|
||||
standaloneTest("lazy3") {
|
||||
source = "runtime/workers/lazy3.kt"
|
||||
}
|
||||
|
||||
task enumIdentity(type: KonanLocalTest) {
|
||||
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
|
||||
goldValue = "true\n"
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.ref.*
|
||||
import kotlin.test.*
|
||||
|
||||
fun main() {
|
||||
test1()
|
||||
test2()
|
||||
}
|
||||
|
||||
fun test1() {
|
||||
ensureGetsCollectedFrozenAndNotFrozen { LazyCapturesThis() }
|
||||
ensureGetsCollectedFrozenAndNotFrozen {
|
||||
val l = LazyCapturesThis()
|
||||
l.bar
|
||||
l
|
||||
}
|
||||
ensureGetsCollected {
|
||||
val l = LazyCapturesThis().freeze()
|
||||
l.bar
|
||||
l
|
||||
}
|
||||
}
|
||||
|
||||
class LazyCapturesThis {
|
||||
fun foo() = 42
|
||||
val bar by lazy { foo() }
|
||||
}
|
||||
|
||||
fun test2() {
|
||||
ensureGetsCollectedFrozenAndNotFrozen { Throwable() }
|
||||
ensureGetsCollectedFrozenAndNotFrozen {
|
||||
val throwable = Throwable()
|
||||
throwable.getStackTrace()
|
||||
throwable
|
||||
}
|
||||
ensureGetsCollected {
|
||||
val throwable = Throwable().freeze()
|
||||
throwable.getStackTrace()
|
||||
throwable
|
||||
}
|
||||
}
|
||||
|
||||
fun ensureGetsCollectedFrozenAndNotFrozen(create: () -> Any) {
|
||||
ensureGetsCollected { create().freeze() }
|
||||
ensureGetsCollected(create)
|
||||
}
|
||||
|
||||
fun ensureGetsCollected(create: () -> Any) {
|
||||
val ref = makeWeakRef(create)
|
||||
kotlin.native.internal.GC.collect()
|
||||
assertNull(ref.get())
|
||||
}
|
||||
|
||||
fun makeWeakRef(create: () -> Any) = WeakReference(create())
|
||||
@@ -9,7 +9,7 @@ import kotlin.native.internal.Frozen
|
||||
|
||||
internal class FreezeAwareLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
|
||||
private val value_ = FreezableAtomicReference<Any?>(UNINITIALIZED)
|
||||
private val initializer_ = FreezableAtomicReference<(() -> T)?>(initializer)
|
||||
private var initializer_: (() -> T)? = initializer
|
||||
private val lock_ = Lock()
|
||||
|
||||
private fun getOrInit(doFreeze: Boolean): T {
|
||||
@@ -25,20 +25,22 @@ internal class FreezeAwareLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
|
||||
// Set value_ to INITIALIZING.
|
||||
value_.value = INITIALIZING
|
||||
try {
|
||||
result = initializer_.value!!()
|
||||
result = initializer_!!()
|
||||
if (doFreeze) result.freeze()
|
||||
} catch (throwable: Throwable) {
|
||||
value_.value = UNINITIALIZED
|
||||
throw throwable
|
||||
}
|
||||
if (!doFreeze && this.isFrozen) {
|
||||
value_.value = UNINITIALIZED
|
||||
throw InvalidMutabilityException("Frozen during lazy computation")
|
||||
if (!doFreeze) {
|
||||
if (this.isFrozen) {
|
||||
value_.value = UNINITIALIZED
|
||||
throw InvalidMutabilityException("Frozen during lazy computation")
|
||||
}
|
||||
// Clear initializer.
|
||||
initializer_ = null
|
||||
}
|
||||
// Set value_ to actual one.
|
||||
value_.value = result
|
||||
// Clear initializer.
|
||||
initializer_.value = null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return result as T
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user