避免 Scala 内存泄漏 - Scala 构造函数 [英] Avoiding Scala memory leaks - Scala constructors
问题描述
我正在阅读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屋!