Zwa*_*ann 5 garbage-collection scala lazy-evaluation
在我目前的项目中,我正在处理大量数据,并且数据处理应该是内存效率和计算性能.每个项目都有一些可以非常快速地读取的元数据,并且几乎总是很有趣.除此之外,每个项目都具有相对较少读取的实际数据,但阅读尤其是解析非常耗时.因此,它自然接缝,只有在实际请求的情况下才能解析数据.
为此我想到了懒惰的价值观:
class Item(metaData: MetaData, dataString: String) {
lazy val data = parse(dataString)
}
Run Code Online (Sandbox Code Playgroud)
现在,仅在实际请求时才解析数据.问题是,dataString和解析后的数据保存在内存中.据我所知,只要"数据"被调用(或者存在?)就不能再访问"dataString"了,因此它可以被垃圾收集.不幸的是,这种接缝不会发生.
有没有办法以不同的方式解决问题或给垃圾收集器提示垃圾收集dataString在这里?
你只需要更多的工具:
class Item(dataString: String) {
private var storedData = dataString
lazy val data = {
val temp = parse(storedData)
storedData = null
temp
}
}
Run Code Online (Sandbox Code Playgroud)
dataString不保留额外的引用,因为你从不在构造函数之外引用它(它设置storedData),并且storedData一旦你使用它就存储在你的引用中,因此字符串可以自由地进行GCed.
它永远不会被垃圾收集的原因是因为Scala存储dataString在私有字段中,因此稍后可以评估惰性函数,因此它dataString永远保留.如果惰性求值发生在一个单独的闭包中,这不会是一个问题,但它只是一个普通的类方法,所以dataString只要类实例是这样的.
您可以通过编译和反汇编类来看到这一点.
class Item(dataString: String) {
lazy val data = parse(dataString)
def parse(s: String) = s.reverse
}
Run Code Online (Sandbox Code Playgroud)
正如反汇编所示,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'
Run Code Online (Sandbox Code Playgroud)