自动装箱的性能影响

发布于 2024-09-13 10:58:37 字数 448 浏览 1 评论 0原文

通常编译器会生成代码来执行装箱和拆箱。但是,如果不需要装箱值,编译器会做什么呢? (Oracle 标准)编译器是否足够智能来优化它?

看一下这个方法:

public static void requireInRange(int index, Object[] array) {
    if(index < 0 || index >= array.length)
        throw new IndexOutOfBoundsException();
}

唯一相关的信息是 array.length,因此对数组的每个值进行装箱是没有用的。就像这段代码一样:

int[] anArray = {3, 4, 2};
requireInRange(3, anArray);

编译器实际上会插入代码来装箱数组的每个值吗?

Usually the compiler generates code to perform boxing and unboxing. But what does the compiler, if the boxed values are not needed? Is the (Oracle standard) compiler smart enough to optimize it away?

Take a look at this method:

public static void requireInRange(int index, Object[] array) {
    if(index < 0 || index >= array.length)
        throw new IndexOutOfBoundsException();
}

The only relevant information is the array.length, so it would be useless to box each value of an array for example. Like in this code:

int[] anArray = {3, 4, 2};
requireInRange(3, anArray);

Will the compiler actually insert code for boxing each value of the array?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

长途伴 2024-09-20 10:58:37

您的代码中没有自动装箱。事实上,假设:

public static void requireInRange(int index, Object[] array) {
   ...
}

int[] anArray = {3, 4, 2};
requireInRange(3, anArray); // DOES NOT COMPILE!!!

虽然 int 可以自动装箱为 Integer,但 int[]不能由 Java 自动装箱为 Integer[]。您可以编写库函数来执行此操作,但该语言不会促进此转换。

这实际上是关于例如 Arrays.asList(anIntArray) 被“损坏”的许多混乱的根源,因为返回的不是 List,而是实际上是一个单元素 List


但性能呢?

引用自 Java 语言指南/Autoboxing

不适合将自动装箱和拆箱用于科学计算或其他性能敏感的数字代码。 Integer 不能替代 int;自动装箱和拆箱模糊了基本类型和引用类型之间的区别,但并没有消除它。

简而言之,每当自动装箱发生时,性能肯定会受到一点影响。某些东西有助于缓解这种情况,例如这些类型中内置的缓存机制。这就是为什么您会得到以下结果:

    System.out.println(
        ((Integer) 0) == ((Integer) 0)
    );
    // true

    System.out.println(
        ((Integer) 10000) == ((Integer) 10000)
    );
    // false (implementation-specific)

这里发生的情况是,当0自动装箱时,没有newInteger实例实际上已创建:出于自动装箱目的缓存特定范围内的值,以提高性能。在大多数实现中,10000 可能超出此范围,但某些 JVM 实现确实允许您在必要时指定缓存范围。


但我只想得到数组的长度!

有很多方法可以帮助您的 requireInRange 处理任何类型的数组。不幸的是,使用 Java 的原语数组通常意味着大量的重复。这意味着为 int[]boolean[]byte[]Object[] 等提供重载分别地。

更简洁的选择是使用反射,但这有其优点和缺点。一般来说,反射不应该是大多数场景的首选解决方案。

话虽如此,java.lang。 Reflect.Array 确实有一个 int getLength(Object array) static 方法,可以返回ANY<的长度/em> 数组。它不是类型安全的(就像大多数反射机制一样);传递非数组可以编译,但在运行时抛出 IllegalArgumentException

相关问题

There is no autoboxing in your code. In fact, given:

public static void requireInRange(int index, Object[] array) {
   ...
}

int[] anArray = {3, 4, 2};
requireInRange(3, anArray); // DOES NOT COMPILE!!!

While an int can be autoboxed to an Integer, an int[] does NOT get autoboxed to Integer[] by Java. You can write library functions to do this, but the language will not facilitate this conversion.

This is in fact the source of many confusion regarding e.g. Arrays.asList(anIntArray) being "broken", because instead of returning a List<Integer>, what is returned is in fact a one-element List<int[]>.


But what about performance???

A quote from Java Language Guide/Autoboxing:

It is not appropriate to use autoboxing and unboxing for scientific computing, or other performance-sensitive numerical code. An Integer is not a substitute for an int; autoboxing and unboxing blur the distinction between primitive types and reference types, but they do not eliminate it.

In short, whenever autoboxing happens, performance definitely takes a little bit of a hit. Certain things help to alleviate this, e.g. the caching mechanism built into these types. This is why you get the following:

    System.out.println(
        ((Integer) 0) == ((Integer) 0)
    );
    // true

    System.out.println(
        ((Integer) 10000) == ((Integer) 10000)
    );
    // false (implementation-specific)

What happened here is that when 0 is automatically boxed, no new Integer instance is actually created: values in certain range is cached for autoboxing purposes, to help performance. 10000 in most implementation probably falls out of this range, but some JVM implementations do allow you to specify the cache range if necessary.


But I just want to get the length of the array!!!

There are many ways to facilitate your requireInRange to work with any type of arrays. Unfortunately working with Java's array of primitives often times mean lots of repetition. This mean providing overloads for int[], boolean[], byte[], Object[], etc separately.

A more concise option is to use reflection, but this has its pluses and minuses. Generally speaking, reflection should not be the preferred solution for most scenarios.

Having said that, java.lang.reflect.Array does have a int getLength(Object array) static method that can return the length of ANY array. It's not typesafe (like most reflection mechanism are); passing a non-array compiles, but throws IllegalArgumentException at run-time.

Related questions

北方的巷 2024-09-20 10:58:37

编译器是否真的插入代码
用于装箱数组的每个值?

编译器将拒绝该代码,因为 int[] 无法传递到采用 Object[] 参数的方法中。

自动装箱仅适用于单个原始值,而不适用于整个数组。

Will the compiler actually insert code
for boxing each value of the array?

The compiler will reject the code because an int[] cannot be passed into a method that takes an Object[] parameter.

Autoboxing happens only for individual primitive values, never for entire arrays.

蓝戈者 2024-09-20 10:58:37

如果有疑问,您可以假设编译器没有优化代码。一般来说,它会对代码进行直译。

此外,如果有疑问,您可以假设 JVM 在运行时优化代码方面做得非常好。我不认为它有任何区别,除非您有充分的理由(例如分析器)怀疑这是一个问题。

If in doubt, you can assume the compiler does not optimize the code. Generally, it does a literal translation of the code.

Additionally, if in doubt, you can assume the JVM does a very good job of optimizing the code at runtime. I wouldn't assume it makes any difference unless you have a good reason (such as profiler) to suspect it is a problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文