JIT编译器如何处理值类型?

5

我正在阅读Jon Skeet的《深入C#》。引用第三章:

JIT可以以特别聪明的方式处理值类型,从而在许多情况下消除装箱和拆箱。 在某些情况下,这可以在速度和内存消耗方面对性能产生巨大影响。

有人能解释一下这是什么意思吗?最好附带一个例子。


“装箱”描述了将值类型保存为“object”的过程,例如:“object o = 13;”,而“拆箱”描述了从对象中检索值的过程:“int thirteen = (int)o;”。这是你想知道的吗? - Nolonar
2
JIT 可以以一种特别聪明的方式处理值类型,从而在许多情况下消除装箱和拆箱。在某些情况下,这可以对性能产生巨大影响,无论是速度还是内存消耗方面。NO. 我想要上述声明的确切含义。 - amitabha
回答这个问题很危险,Jon有很多粉丝。但据我所知他是错的(躲避那道闪电)。Jitter的SSCLI20版本在编译器要求盒子时肯定会盒化值类型。是C#编译器可以使用Opcodes.Constrained而不是Opcodes.Box来省略盒子。再说了,那个Jitter版本与我们每天使用的版本不匹配,也许在泛型方法的一个角落里允许在运行时省略盒子,这是可行的。 - Hans Passant
@HansPassant:我并没有谈论到那个层面上的任何内容,我想这与JIT也没有太大关系。更多的是,在C# 1中需要装箱的情况在C# 2中不再需要装箱,因此JIT不会执行无意义的装箱操作。我并不是在尝试暗示它忽略了编译器所需的任何装箱。 - Jon Skeet
2个回答

1
让我们以 List<int> 为例。它由真正的 int[] 支持,JIT 将专门为 int 类型参数编译代码,因此在 List<T> 中使用 T 的任何代码都应该得到任何优化,就像该代码仅适用于整数一样。
与 Java 的泛型相比,只有类类型是有效的类型参数 - 因此即使写入以下内容也是有效的:
// Java code!
List<Integer> integers = new ArrayList<Integer>();
integers.add(10);
int x = integers.get(0); // x = 10

这会在后台执行装箱和拆箱操作。相应的C#代码根本不涉及任何装箱。


非常感谢Jon。但是Jon,您能否更详细地解释下面这行代码的含义:使得在List<T>中使用T的任何代码都可以获得优化,就好像该代码是针对整数编写的一样。 - amitabha

0

我认为Jon的意思是许多这些类型并不被视为其定义类型的对象。例如,int类型不必被视为结构体,并且可以直接在寄存器中处理。两个整数的相加不是通过重载操作符来处理,而是由CPU直接完成。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接