如何减少Scala中创建的对象数量?

Phi*_*hil 11 memory garbage-collection jvm memory-management scala

我在Scala中编写了一个计算机图形应用程序,它使用RGB类来返回图像中某个点的颜色.可以想象,返回颜色RGB对象的函数被多次调用.

class RGB(val red: Int, val green: Int, val blue: Int) { }
Run Code Online (Sandbox Code Playgroud)

有一个函数getPixelRGB,经常使用如下

val color:RGB = getPixelRGB(image, x, y)
Run Code Online (Sandbox Code Playgroud)

问题是我可能会将这个函数调用一百万次,我相信这会生成一百万个唯一的RGB对象实例,这是一个非常不吸引人的情况.我对此有一些想法:

  1. getPixelRGB可能会创建无限数量的对象(如果它被无限次调用),但它不一定是无限数量的对象,因为只有最多可以为RGB生成255*255*255种可能的组合.所以创建的对象数量"应该"是有限的.可以调整此函数以使用对象池,如果要返回相同的颜色,则可以返回该颜色之前的相同池化对象实例.

  2. 我可以将这个RGB编码为Int.Int比普通的Scala/Java对象具有更少的内存开销,Java对象有额外的内存开销.由于Scala Int类型的宽度为4个字节,因此前3个字节可以存储RGB值.仅从getPixelRGB方法返回Int而不是RGB将会减少我假设的内存开销.但是如何在仍然拥有RGB类的说服力的同时做到这一点?

  3. 据说,它们是短暂存在的对象,我已经读过垃圾收集器应该快速重新声明它们.不过我还是很担心.GC如何知道我快速扔掉它?太混乱了.

所以一般来说,我的问题是如何使这个getPixelRGB更加内存友好?我还应该担心吗?

om-*_*nom 13

您可以使用单个longint 对RGB进行编码.此外,在scala 2.10中,您可以为原始值定义值类,比如说

class RGB private(val underlying: Long) extends AnyVal {
  def toTriple = /*decoding to (red, green, blue)*/
} 
object RGB {
  def apply(red: Int, green: Int, blue: Int) = /* encode and create class with new RGB(longvalue)*/
}
Run Code Online (Sandbox Code Playgroud)

使用值类,您仍然可以获得类型信息,并在JVM中享受无类内存布局.


Pét*_*rök 5

你的问题#3还没有解决,所以我会试一试.

GC如何知道我快速抛弃[短寿命物体]?

现代地方选区的工作是基于观察到不同生命期的物体表现得非常不同.所以它在所谓的世代中管理它们.刚创建的对象存储在eden空间中.当它填满时,其中仍然被引用的所有对象(即它们都是活着的)被复制到所谓的年轻代空间.因此,所有死亡的物体都被留下,并且它们占据的空间几乎没有任何回收.这就是使短期对象对JVM如此便宜的原因.并且平均程序创建的大多数对象都是临时或局部变量,这些变量很快就会超出范围.

在第一轮GC之后,年轻一代的空间以类似的方式进行管理,除了可能有更多的空间.可以将GC配置为使对象在年轻代空间中花费一轮或多轮.然后最终,最后的幸存者被迁移到幸存者(又名老一代)空间,他们将在那里度过余生.通过定期应用经典标记和扫描技术的一些变体来管理此空间:遍历所有实时参考的图形并标记活动对象,然后通过将幸存者压缩成一个连续的内存块来清除所有未标记(死亡)的对象,从而对自由记忆进行碎片整理.这是一种阻碍程序执行的昂贵操作,并且很难正确实现它,尤其是在现代多线程VM中.这就是发明分代GC的原因,以确保创建的所有对象中只有一小部分能够进入这个阶段.