2010-12-09 4 views
4

Хотел бы поиграть с scala.ref.WeakReference. Однако, прежде чем пытаться реализовать большую вещь, я хотел бы попытаться проверить поведение в консоли scala. Я пробовал кое-что, но я не смог получить свой объект, чтобы разыменоваться. Вот одна из моих попыток:WeakReference и Scala REPL

> class A 
defined class A 

> class B(var value: A) 
defined class B 

> new B(new A) 
res0: B = [email protected] 

> new scala.ref.WeakReference(res0.value) 
res1: scala.ref.WeakReference[A] = [email protected] 

> res0.value = new A 

> res1.get // Here I hope to get None 
res3: Option[A] = Some([email protected]) 

Еще одна попытка дана oxbow_lakes ниже.

Я также попытался явно запустить сборщик мусора (призывая java.lang.System.gc) впустую.

Есть ли способ разыменовать содержимое res1?

+0

Как вы можете видеть, мы сильно смущены о том, REPL делает, что REPL говорит, что это делает, и что REPL должен делать, и когда GC пропустит сбор неопубликованного объекта. Есть ли вероятность, что вы можете написать сценарий Scalaв ** файле **, который проверяет поведение, которое вы хотите, и посмотрите, работает ли это, поэтому вам не нужно беспокоиться о капризе того, как REPL печатает свой результат? – 2010-12-09 17:04:16

ответ

5
Welcome to Scala version 2.8.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_22). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> class A 
defined class A 

scala> class B(var value: A) 
defined class B 

scala> new B(new A) 
res0: B = [email protected] 

scala> new scala.ref.WeakReference(res0.value) 
res1: scala.ref.WeakReference[A] = [email protected] 

scala> res0.value = new A 

scala> System gc 

scala> res1 get 
res3: Option[A] = None 

Кстати, если я запускаю его как сценарий без явного System gc, он не будет удалить ссылку либо. Поэтому для меня это не проблема REPL, а только то, как работают слабые ссылки и сборщик мусора.

+0

+1: Это определенно REPL quirk. Ваше решение просто делает это так, чтобы REPL не сохранял прямую ссылку на первое значение «var», которое я указал в своем ответе. Но REPL будет держать прямую ссылку на ** второе ** значение, которое вы дали `res0.value`, поэтому вы полностью не решили проблему для экспериментов в целом. – 2010-12-09 16:42:00

+0

Ну, я просто выполнил исходный вопрос ... – Debilski 2010-12-09 16:45:24

0

Моя идея состояла в том, чтобы использовать var явно и установить на null:

scala> var b = new B(new A) 
b: B = [email protected] 

scala> new scala.ref.WeakReference(b.value) 
res0: scala.ref.WeakReference[A] = [email protected] 

scala> b = null 
b: B = null 

scala> res0.get 
res1: Option[A] = Some([email protected]) 

Он по-прежнему не работает, хотя: РЕПЛ предположительно делать вещи под одеялом, который держит в руки ссылки. Поэтому я не советую использовать его для тестирования использования Reference.

+0

Это была одна из других попыток. Это тоже не работает. Я также опасаюсь, что REPL не скрывает ссылки на объекты. – Nicolas 2010-12-09 13:48:55

+1

Да - мои тесты показали то же самое. Я сохранил ответ для полноты – 2010-12-09 13:51:06

0

От Docs API Java:

Вызов метода дс предполагает, что виртуальной машины расходуют усилия Java в направлении утилизации неиспользуемых объектов в для того, чтобы память, которую они в настоящее время занимают для быстрого повторного использования. Когда управление возвращается из вызова метода , виртуальная машина Java приложила все усилия, чтобы вернуть пространство от всех отброшенных объектов.

В моем опытном опыте это означает, что он редко запускает по-настоящему полную коллекцию, особенно если нет никакого давления с точки зрения доступной памяти. Если вы окажетесь на нем, он будет собран. Я думаю, вы ожидаете более детерминированного поведения из GC, чем это предусмотрено.

Welcome to Scala version 2.8.0.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_22). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> var s = new String("Hello, world!")   
s: java.lang.String = Hello, world! 

scala> import scala.ref.WeakReference 
import scala.ref.WeakReference 

scala> val w = new WeakReference(s) 
w: scala.ref.WeakReference[java.lang.String] = [email protected] 

scala> s = null 
s: java.lang.String = null 

scala> Array.ofDim[Byte](1024*1024) 
res1: Array[Byte] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 
scala> Array.ofDim[Byte](1024*1024) 
res2: Array[Byte] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 
scala> Array.ofDim[Byte](1024*1024) 
res3: Array[Byte] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 
scala> Array.ofDim[Byte](1024*1024) 
res4: Array[Byte] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 
scala> Array.ofDim[Byte](1024*1024) 
res5: Array[Byte] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 
scala> Array.ofDim[Byte](1024*1024) 
res6: Array[Byte] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 
scala> System.gc 

scala> var g = w.get 
g: Option[java.lang.String] = None 
1

запустить свой код с scala -Xprint:parser, и вы увидите, что держит старое значение в var ссылается даже после того, как вы переназначить его.

Я собираюсь упростить вещи здесь, и просто запустить две строки кода:

var b=1 
b=2 

И это то, что Scala печатает:

scala> var b=1 
[[syntax trees at end of parser]]// Scala source: <console> 
package <empty> { 
    object line2$object extends scala.ScalaObject { 
    def <init>() = { 
     super.<init>(); 
    () 
    }; 
    object $iw extends scala.ScalaObject { 
     def <init>() = { 
     super.<init>(); 
     () 
     }; 
     object $iw extends scala.ScalaObject { 
     def <init>() = { 
      super.<init>(); 
     () 
     }; 
     var b = 1        ///// YOUR CODE HERE 
     } 
    } 
    } 
} 

[[syntax trees at end of parser]]// Scala source: <console> 
package <empty> {        /////THIS IS AN object 
               /////SO PRESUMABLY IT CAN'T BE GC'ED 
    object RequestResult$line2$object extends scala.ScalaObject { 
    def <init>() = { 
     super.<init>(); 
    () 
    }; 
    lazy val scala_repl_value = {     /////THIS LAZY VAL 
     scala_repl_result;       /////WILL REFERENCE THE OLD VALUE 
     line2$object.$iw.$iw.b      /////EVEN AFTER YOU REASSIGN THE var 
    }; 
    val scala_repl_result: String = { 
     line2$object.$iw.$iw; 
     "".$plus("b: Int = ").$plus(scala.runtime.ScalaRunTime.stringOf(line2$object.$iw.$iw.b)) 
    } 
    } 
} 

b: Int = 1 

scala> b=2 
[[syntax trees at end of parser]]// Scala source: <console> 
package <empty> { 
    object line3$object extends scala.ScalaObject { 
    def <init>() = { 
     super.<init>(); 
    () 
    }; 
    object $iw extends scala.ScalaObject { 
     def <init>() = { 
     super.<init>(); 
     () 
     }; 
     import line2$object.$iw.$iw.b;    ///// I DON'T THINK THIS (ORDINARILY ILLEGAL) 
                ///// import CONTRIBUTES TO THE PROBLEM 
     object $iw extends scala.ScalaObject { 
     def <init>() = { 
      super.<init>(); 
     () 
     }; 
     b = 2;         /////YOUR CODE HERE 
     val synthvar$0 = b 
     } 
    } 
    } 
} 

[[syntax trees at end of parser]]// Scala source: <console> 
package <empty> { 
    object RequestResult$line3$object extends scala.ScalaObject { 
    def <init>() = { 
     super.<init>(); 
    () 
    }; 
    lazy val scala_repl_value = { 
     scala_repl_result; 
     line3$object.$iw.$iw.synthvar$0 
    }; 
    val scala_repl_result: String = { 
     line3$object.$iw.$iw; 
     "".$plus("b: Int = ").$plus(line3$object.$iw.$iw.synthvar$0).$plus("\012") 
    } 
    } 
} 

b: Int = 2 

EDIT: Для добавьте на Debilski's answer, я думаю, что следующее решение позволит вам переназначить переменную столько раз, сколько вы захотите, если REPL не будет ссылаться на старое значение:

class A 
class B{ 
    var _value:A = new A 
    def value = _value 
    def pleaseUpdate(closure: B => Unit) = closure(this) 
} 

Определите объект контейнера, как:

val b=new B 

И всякий раз, когда вы хотите обновить переменную, которая находится внутри него:

b.pleaseUpdate(_._value = new A) 
Смежные вопросы