它永远不会被垃圾收集的原因是因为 Scala 存储dataString
在一个私有字段中,因此惰性函数可以稍后被评估,所以它dataString
永远保持不变。如果惰性求值发生在单独的闭包中,这不会有问题,但它只是一个普通的类方法,所以dataString
只要类实例存在,它就会被保存。
您可以通过编译和反汇编类来看到这一点。
class Item(dataString: String) {
lazy val data = parse(dataString)
def parse(s: String) = s.reverse
}
如反汇编所示,创建了一个最终的私有字段,该字段dataString
存储在构造函数中。惰性求值发生在data$lzycompute
获取值dataString
、对其执行计算并将结果存储在data
字段中的方法中。但dataString
仍保有其原始价值。
它还定义了一个字段bitmap$0
来跟踪惰性函数是否已被评估,以及一个包装访问器成员也被data
调用,如果需要,它会调用该函数,然后返回该字段data
。
.version 50 0
.class super public Item
.super java/lang/Object
.runtimevisible annotation Lscala/reflect/ScalaSignature;
bytes = string [_7]
.end annotation
.attribute ScalaSig '\x05\x00\x00'
.field final private dataString Ljava/lang/String;
.field private data Ljava/lang/String;
.field volatile private bitmap$0 Z
.method private data$lzycompute : ()Ljava/lang/String;
.limit stack 3
.limit locals 2
.catch [0] from L4 to L34 using L46
aload_0
dup
astore_1
monitorenter
L4:
aload_0
getfield Item bitmap$0 Z
ifne L28
aload_0
aload_0
aload_0
getfield Item dataString Ljava/lang/String;
invokevirtual Item parse (Ljava/lang/String;)Ljava/lang/String;
putfield Item data Ljava/lang/String;
aload_0
iconst_1
putfield Item bitmap$0 Z
L28:
.stack append
locals Object Item
.end stack
getstatic scala/runtime/BoxedUnit UNIT Lscala/runtime/BoxedUnit;
pop
aload_1
monitorexit
L34:
aload_0
aconst_null
pop
aconst_null
putfield Item dataString Ljava/lang/String;
aload_0
getfield Item data Ljava/lang/String;
areturn
L46:
.stack same_locals_1_stack_item
stack Object java/lang/Throwable
.end stack
aload_1
monitorexit
athrow
.end method
.method public data : ()Ljava/lang/String;
.limit stack 1
.limit locals 1
aload_0
getfield Item bitmap$0 Z
ifeq L14
aload_0
getfield Item data Ljava/lang/String;
goto L18
L14:
.stack same
aload_0
invokespecial Item data$lzycompute ()Ljava/lang/String;
L18:
.stack same_locals_1_stack_item
stack Object java/lang/String
.end stack
areturn
.end method
.method public parse : (Ljava/lang/String;)Ljava/lang/String;
.limit stack 4
.limit locals 2
new scala/collection/immutable/StringOps
dup
getstatic scala/Predef$ MODULE$ Lscala/Predef$;
aload_1
invokevirtual scala/Predef$ augmentString (Ljava/lang/String;)Ljava/lang/String;
invokespecial scala/collection/immutable/StringOps <init> (Ljava/lang/String;)V
invokeinterface scala/collection/IndexedSeqOptimized reverse ()Ljava/lang/Object; 1
checkcast java/lang/String
areturn
.end method
.method public <init> : (Ljava/lang/String;)V
.limit stack 2
.limit locals 2
aload_0
aload_1
putfield Item dataString Ljava/lang/String;
aload_0
invokespecial java/lang/Object <init> ()V
return
.end method
.const [_7] = Utf8 '\x06\x01)2A!\x01\x02\x01\x0b\t!\x11\n^3n\x15\x05\x19\x11a\x02\x1ff[B$\x18PP\x02\x01\'\t\x01a\x01\x05\x02\x08\x195\t\x01B\x03\x02\n\x15\x05!A.\x198h\x15\x05Y\x11\x01\x026bm\x06L!!\x04\x05\x03\r=\x13\'.Z2u\x11!y\x01A!A!\x02\x13\x01\x12A\x033bi\x06\x1cFO]5oOB\x11\x11c\x06\x08\x03%Ui\x11a\x05\x06\x02)\x05)1oY1mC&\x11acE\x01\x07!J,G-\x1a4\n\x05aI"AB*ue&twM\x03\x02\x17\'!)1\x04\x01C\x019\x051A(\x1b8jiz""!H\x10\x11\x05y\x01Q"\x01\x02\t\x0b=Q\x02\x19\x01\t\t\x11\x05\x02\x01R1A\x05\x02\t\nA\x01Z1uCV\t\x01\x03\x03\x05%\x01!\x05\t\x15)\x03\x11\x03\x15!\x17\r^1!\x11\x151\x03\x01"\x01(\x03\x15\x01\x18M]:f)\t\x01\x02\x06C\x03*K\x01\x07\x01#A\x01t\x01'