scala类型系统:21) type specialization与类爆炸

Type Specialization的paper,这里也已经有翻译了。简单的说,就是出于性能考虑,避免基础类型的装箱拆箱,为基础类型保留了特定的实现。

class V[@specialized T]{
    var i:T = _
}

上面用了specialized注释,除了定义一个泛型的V[A],之外,编译器还会额外生成9个特定的类型:

% scalac V.scala && ll
-rw-r--r--  1 hongjiang  wheel  1060 11  5 16:07 V$mcB$sp.class
-rw-r--r--  1 hongjiang  wheel  1070 11  5 16:07 V$mcC$sp.class
-rw-r--r--  1 hongjiang  wheel  1066 11  5 16:07 V$mcD$sp.class
-rw-r--r--  1 hongjiang  wheel  1063 11  5 16:07 V$mcF$sp.class
-rw-r--r--  1 hongjiang  wheel  1065 11  5 16:07 V$mcI$sp.class
-rw-r--r--  1 hongjiang  wheel  1060 11  5 16:07 V$mcJ$sp.class
-rw-r--r--  1 hongjiang  wheel  1063 11  5 16:07 V$mcS$sp.class
-rw-r--r--  1 hongjiang  wheel  1032 11  5 16:07 V$mcV$sp.class
-rw-r--r--  1 hongjiang  wheel  1063 11  5 16:07 V$mcZ$sp.class
-rw-r--r--  1 hongjiang  wheel  3549 11  5 16:07 V.class
-rw-r--r--  1 hongjiang  wheel    41 11  5 16:07 V.scala

hongjiang@whj-mbp /tmp/dd % javap V\$mcD\$sp     
Compiled from "V.scala"
public class V$mcD$sp extends V{
    public double i$mcD$sp;
    public double i$mcD$sp();
    public double i();              // 这个是针对double类型的
    public void i$mcD$sp_$eq(double);
    public void i_$eq(double);
    public boolean specInstance$();
    public void i_$eq(java.lang.Object);
    public java.lang.Object i();
    public V$mcD$sp();
}

从上面看到,哪些匿名类的类名中的:B,C,D,F,I,J,S,V,Z,分别对应 byte,char,double,float,int,long,short,void(scala里的Unit), boolean

在类型参数比较多的情况下,specialization会产生类爆炸的情况,参考stackoverflow上的一个例子

class Huge[@specialized A, @specialized B, @specialized C](
  val a: A, val b: B, val c: C
) {} // 730 files, 2.9 MB

上面的类产生了730个文件:9x9x9+1。之前在模拟perm gen的oom时,用到过这个特性。

//2012.5.30
在REPL下,模拟perm gen的oom案例:

虽然perm gen确实在不断增加,并且可能会OOM(如果perm gen设置比较小的话),但通过jconsole的类加载来看并非把这些定义的class都load了;对比了前后的class load

之前:3797 个class被load

运行一次:

class Test[@specialized A, @specialized B, @specialized C, @specialized D]

之后:4180 ,增加了383个而不是 9x9x9x9=6561个 why?

通过jvisualvm工具dump了前后的内存对比,scala.tools.nsc.io.VirtualFile 实例数从2增加到了 6573,增长了 6571 个,并且每运行一次都会增加 6571个,比6561多出10个

继续测试

class Test[@specialized A] 

也是会使 VirtualFile 新增 19个而非9个,另外多出来的10个实例还没有清楚是什么。

Leave a Reply

Your email address will not be published. Required fields are marked *