从内存中清除懒惰值
我正在写一个JRPG风格的游戏,并且在YAML文件中定义我的物品/敌人等。不是在运行时加载它们(这在Scala中被证明是一种痛苦,尤其是在Android上),我决定将它们作为惰性值预编译为Scala对象。从内存中清除懒惰值
我唯一担心的是,最终,随着这些值被访问,对象将开始占用比真正需要更多的内存。
无论如何重新初始化一个Scala对象或清除懒惰值回到其默认状态?或者,有没有更好的方法来完成我在这里要做的事情?
没有这样的机制。一旦访问了lazy val
并且对其初始值设定项进行了评估,则结果值将保存在与其它任何其他实例相同的实例的字段中,并且只有该实例变为垃圾本身才会放弃对该“懒惰”值的引用,并可能)允许它被回收。当然,如果还有其他的引用,它们将阻止它被回收。
我认为它没有内置的机制,所以你需要自己实现它。最简单的解决方案是在某些时间过后有某种形式的缓存到期 - 例如,如Java time-based map/cache with expiring keys中所述。
这取决于你是否有 - 我们称之为“弱值” - 对于不同类型或弱值的一种类型,但涉及许多对象。如果你有后者,我会使用Rogach使用地图/缓存的解决方案。
但是,如果您拥有第一个不同的课程或者一些大对象 - 一种方法肯定是使用WeakReference。
这是我想出了一个解决办法 - 也许在未来,这可能与宏来完成:
object UseWeakRef extends App {
import scala.ref.WeakReference
class WeakRefCreator[T <: AnyRef] {
private var weakRef: WeakReference[T] = WeakReference(null.asInstanceOf[T])
def apply(creator: => T): T = weakRef.get match {
case None =>
val newVal: T = creator
weakRef = WeakReference(newVal); newVal
case Some(value) => value
}
}
private val expensiveRef = new WeakRefCreator[String]
def expensiveVal = expensiveRef {
println("creating expensive object")
"This is expensive"
}
println(expensiveVal)
println(expensiveVal)
}
输出BTW是:
creating expensive object
This is expensive
This is expensive
我觉得软(不弱)的引用这非常方便。弱引用会被每个不需要的GC所占用,如果它们被重复访问,会浪费很多精力。只有在存在内存压力时才会使用软引用(正式可能是每个GC,但至少JVM可以自行决定)。总之,对于Scala的使用,这是非常方便的:
class Soft[T,U](t: T)(gen: T => U) {
private[this] var cache = new java.lang.ref.SoftReference(gen(t))
def apply(): U = {
var u = cache.get()
if (u==null) {
u = gen(t)
cache = new java.lang.ref.SoftReference(u)
}
u
}
}
object Soft {
def apply[T,U](t: T)(gen: T => U) = new Soft(t)(gen)
}
现在你包裹在Soft
东西适量,当你想要它使用()
获取数据:
val soft = Soft(10)(n => Array.tabulate(n)(i => i*i*i))
soft()(3) // 27
获得软参考(通常等于几个对象创建)的惩罚并不是完全可以忽略的,所以如果您要使用某些东西,请先抓住它,然后执行该操作:
val arr = soft()
// Intensive operations with arr
通过使用代码生成方法,您将始终拥有代码形式的对象的至少一个副本来构造对象,并且可能还有另一个对象本身。构建数据的代码可能比实际对象使用更多的内存。
我建议你暂时忽略这个内存管理问题 - 不要使用懒惰的vals或soft引用或任何其他的释放机制。如果你的目标不是低内存环境(移动设备),那么你可以允许操作系统“交换”构造代码和大部分数据(在本地类型的字符串和数组中的数据)时间。
由于您仍然拥有原始的YAML文件,如果您发现游戏的这部分内容使用了太多内存,则可以在游戏制作的波兰/优化阶段恢复从数据文件加载。