在类ObjectToBeCached
上,我们有一个lazy val
,以避免对数据库的多个请求。同样缓存case class
的{{1}}缓存(播放框架,内存缓存)lazy val
上的对象。问题是对象相当大并且消耗了相当多的内存。
有没有什么方法可以绕过lazy val本身的缓存,或者在没有缓存主lazy val
的大子对象的情况下为case class
提供优势的替代解决方案?< / p>
case class ObjectToBeCached() {
lazy val someAttribute:Option[BigObject] = retrieveBigObjectFromDatabase()
}
感谢任何提示!
更新
有时,我在最初发布此问题时没有使用正确的术语。因为这个问题磕磕绊绊,面对类似的挑战。
我一直在寻找一种方法来避免类ObjectToBeCached
的lazy val的序列化,因为lazy val会消耗太多的缓存。
因此,标题应该是如何避免lazy val的序列化?
答案 0 :(得分:2)
当然,如果没有缓存对象,又不需要从数据库中获取它,那么你就不能吃蛋糕了。如果您确定拥有磁盘空间并且这比数据库检索快得多,您可以自己创建内存不足的缓存(在磁盘或其他东西上)。 (但数据库的构建非常适合这种事情。)
如果对象是临时的,那么尝试将其置于计算中:
lazy val keepThisForever = {
val cacheThisForRightNow = readFromDB()
f(cacheThisForRightNow)
...
answer
}
或者如果不可能,将其分配给var并在可能时手动清除它。
或者,如果你想要缓存的项目,但只有你有足够的内存来存储它,你可以使用软引用,它可以这样封装:
// Use this to cache expensive computations that are cleared when
// memory gets especially tight (via SoftReference); not thread-safe
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)
}
现在你可以
val queryResult = Soft(queryString)(readFromDB)
并使用
进行访问queryResult()
您可以在需要时从数据库中读取数据。
(如果您需要线程安全,则必须至少将调用同步到apply
,如果您尝试让多个线程在创建后立即使用该对象,则必须更多。)
如果你的意思是你不希望lazy val序列化(你最初没有在你的问题中提出这个问题!),这就是@transient
注释的用途。
答案 1 :(得分:1)
如果查询中长期需要的内容比结果集本身小得多,则可以使用这种模式:
lazy val queryResult = {
val resultSet = doTheQuery(...)
extractQueryInfo(resultSet)
}
现在查询将按需执行,原始查询结果将被垃圾收集,只保留派生信息。
答案 2 :(得分:0)
我认为您有兴趣按需创建价值,但不会永远保持价值。在这种情况下,请将lazy val
更改为def
。