2013-03-16 5 views
1

현재 JRPG 스타일의 게임을 작성 중이며 YAML 파일에 내 아이템/적을 정의하고 있습니다. 런타임에 (특히, 안드로이드에서 Scala에서 고통 스러울 것으로 판명되는) 런타임에로드하는 대신, 스칼라 객체를 게으른 값으로 미리 컴파일하기로 결정했습니다.메모리에서 게으른 값 지우기

궁극적으로 이러한 값에 액세스 할 때 객체는 실제로 필요한 것보다 많은 메모리를 차지하기 시작합니다.

어쨌든 Scala 객체를 다시 초기화하거나 지연 값을 기본 상태로 되돌려 놓을 수 있습니까? 또는, 여기서 내가하려고하는 것을 성취 할 수있는 더 좋은 방법이 있습니까?

답변

2

이러한 메커니즘은 없습니다. 일단 lazy val이 액세스되고 이니셜 라이저가 평가되면 결과 값은 다른 인스턴스와 마찬가지로 인스턴스의 필드에 보관되고 그 인스턴스 만 가비지가되어 "게으른"값에 대한 참조를 포기하고 (가능하게) 그것을 또한 개심 케 할 수 있습니다. 당연히 다른 참조 사항이있을 경우 해당 참조가 회수되는 것을 방지합니다.

1

기본 메커니즘이 없으므로 직접 구현해야합니다. 가장 간단한 해결책은 특정 시간이 지나면 만료되는 캐시의 형태를 갖는 것입니다 (예 : Java time-based map/cache with expiring keys에서 설명).

1

한 가지 유형의 약한 값이나 약한 값에 대해서는 "약한 값"이라고 부르지 만 관련 개체가 많으면 다릅니다. 후자가 있다면 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 
7

내가 찾을 수는 (약한되지 않음) 참조 소프트 이것을 위해 매우 편리합니다. 약한 참조는 필요하지 않은 모든 GC를 먹어서 반복적으로 액세스하면 많은 노력을 낭비 할 수 있습니다. 소프트 참조는 메모리 압력이있을 때만 먹습니다 (공식적으로 모든 GC 일 수 있지만 최소한 JVM은 약간의 재량권을 행사할 수 있음).

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 
1

코드 생성 방법을 사용하면 개체를 구성하는 코드 형태로 개체의 복사본을 하나 이상 가질 수 있으며 개체 자체에서 다른 개체를 만들 수 있습니다. 데이터를 생성하는 코드는 실제 객체보다 많은 메모리를 사용하고있을 가능성이 큽니다.

잠시 동안이 메모리 관리 문제를 모두 무시하는 것이 좋습니다 - 지연 값 또는 소프트 참조 또는 다른 할당 취소 스키마를 사용하지 마십시오. 낮은 메모리 환경 (모바일 장치)을 목표로하지 않는 경우 운영 체제에서 건설 코드와 많은 데이터 (문자열 및 기본 유형의 배열에있는 데이터)를 "교환"할 수 있습니다. 시각.

여전히 원래 YAML 파일이 있으므로 게임의이 부분이 너무 많은 메모리를 사용하고 있음을 발견하면 게임 제작의 연마/최적화 단계에서 데이터 파일에서 다시로드 할 수 있습니다.