避免 Scala 内存泄漏 - Scala 构造函数 [英] Avoiding Scala memory leaks - Scala constructors

查看:73
本文介绍了避免 Scala 内存泄漏 - Scala 构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读Scala 编程"一书,但在第 6 章中实现类 Rational 时遇到了一个小问题.

I was working through the "Programming in Scala" book, and was struck by a bit of a problem in the implementation of the class Rational in Chapter 6.

这是我的 Rational 类的初始版本(基于本书)

This is my initial version of the Rational class (based on the book)

class Rational(numerator: Int, denominator: Int) {
  require(denominator != 0)

  private val g = gcd(numerator.abs, denominator.abs)

  val numer = numerator / g
  val denom = denominator / g

  override def toString  = numer + "/" + denom

  private def gcd(a: Int, b: Int): Int =
    if(b == 0) a else gcd(b, a % b)

  // other methods go here, neither access g
}

这里的问题是字段 g 在类的整个生命周期中都会保留,即使再也不会被访问.这个问题可以通过运行下面的模拟程序看到:

The problem here is that the field g remains for the lifetime of the class, even if never again accessed. This problem can be seen by running the following mock program:

object Test extends Application {

  val a = new Rational(1, 2)
  val fields = a.getClass.getDeclaredFields

  for(field <- fields) {
    println("Field name: " + field.getName)
    field.setAccessible(true)
    println(field.get(a) + "\n")
  }  

}

它的输出将是:

Field: denom
2

Field: numer
1

Field: g
1

我在 Scala Wiki 上找到的解决方案涉及以下内容:

A solution I found at the Scala Wiki involves the following:

class Rational(numerator: Int, denominator: Int) {
  require(denominator != 0)

  val (numer, denom) = { 
    val g = gcd(numerator.abs, denominator.abs)
    (numerator / g, denominator / g)
  }

  override def toString  = numer + "/" + denom

  private def gcd(a: Int, b: Int): Int =
    if(b == 0) a else gcd(b, a % b)

  // other methods go here
}

此处,字段 g 仅在其块的本地,但是,运行小型测试应用程序时,我发现了另一个字段 x$1,它保留了由 (numer, denom)!

Here, the field g is only local to its block, but, running the small test application, I found another field x$1 which keeps a copy of the tuple consisting of (numer, denom)!

Field: denom
2

Field: numer
1

Field: x$1
(1,2)

有没有什么办法可以用上面的算法在Scala中构造一个有理数,而不会造成任何内存泄漏?

Is there any way to construct a rational in Scala with the above algorithm, without causing any memory leaks?

谢谢,

弗拉维乌·西皮根

推荐答案

你可以这样做:

val numer = numerator / gcd(numerator.abs, denominator.abs)
val denom = denominator / gcd(numerator.abs, denominator.abs)

当然,您必须进行两次计算.但是优化通常是内存/空间和执行时间之间的权衡.

Of course you'd have to do the calculation twice. But then optimizations are often a trade-off between memory/space and execution time.

也许还有其他方法,但是程序可能会变得过于复杂,如果有一个地方的优化很少为时过早,那就是脑力优化:).例如,您可能可以这样做:

Maybe there are other ways too, but then the program might get overly complex, and if there's one place where optimization is rarely premature, it's brain power optimization :). For instance, you could probably do this:

val numer = numerator / gcd(numerator.abs, denominator.abs)
val denom = denominator / (numerator / numer)

但这并不一定会使代码更易于理解.

But it doesn't necessarily make the code more understandable.

(注意:我实际上没有尝试过,所以使用风险自负.)

(Note: I didn't actually try this, so use at your own risk.)

这篇关于避免 Scala 内存泄漏 - Scala 构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆