Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 短->;int->;长型促销:有开销吗?_Java_Performance_Jvm Bytecode - Fatal编程技术网

Java 短->;int->;长型促销:有开销吗?

Java 短->;int->;长型促销:有开销吗?,java,performance,jvm-bytecode,Java,Performance,Jvm Bytecode,例如,如果我将方法的返回类型/参数定义为char,但调用者和实现实际上立即将其用作int,是否有任何开销?如果我理解正确,堆栈上的值无论如何都是32位对齐的,“寄存器”也是如此(对不起,我不太熟悉字节码) 在您进行否决表决或在阅读之前关闭之前,请给出一个解释:我正在编写用于解析和格式化二进制流的低级代码。我需要一个单个位的表示,用于索引流以读取和更新单个位。这是Scala,我使用的是一个值类,这是一个在编译时被删除为所选java原语类型的构造。这意味着方法定义为: class Bit(val t

例如,如果我将方法的返回类型/参数定义为
char
,但调用者和实现实际上立即将其用作
int
,是否有任何开销?如果我理解正确,堆栈上的值无论如何都是32位对齐的,“寄存器”也是如此(对不起,我不太熟悉字节码)

在您进行否决表决或在阅读之前关闭之前,请给出一个解释:我正在编写用于解析和格式化二进制流的低级代码。我需要一个单个位的表示,用于索引流以读取和更新单个位。这是Scala,我使用的是一个值类,这是一个在编译时被删除为所选java原语类型的构造。这意味着方法定义为:

class Bit(val toInt :Int) extends AnyVal

@inline def +=(bit :Bit) = ...
@inline def +=(int :Int) = ...
编译时相互冲突,因为它们在字节码中都是
$加$eq$(int)
。 很明显,有很多方法可以解决这个问题,其中的主要方法是以不同的方式命名方法,但我宁愿避免使用它,以防它不重要。
int
是位表示的自然选择,因为它是任何按位操作的结果,因此从
word>>offset&1
位的“转换”是不可操作的,同样,它们也可以在不需要任何操作的情况下放入按位表达式中。正如你所看到的,非常细粒度的东西

我不会使用
boolean
,因为在转换为
int
或从
int
转换时,似乎没有任何方法可以绕过条件表达式,但我考虑了
char
,否则它将不被使用(也就是说,不需要读和写一个字符,因为它们是比我在这个级别处理的抽象概念高得多的抽象概念)


那么,将
char
s放入按位操作是否会影响任何事情,或者它比方法调用快两个数量级(如创建和弹出激活记录的开销)?

问题是,您的问题本质上是无法回答的

从字节码的角度来看,是的,这是有开销的:您可以使用
javap-c
来“反汇编”类文件(显示字节码),并且您会发现类型升级是由实际的字节码处理的。例如:

class Test {
   void example() {
        int a = 0;
        long b = 0L;
        foo(a);
        foo(b);
    }

   void foo(long c) {}
}
然后

它向您展示了当
int
提升为
long
时,会涉及到
I2L
操作码,而如果您直接使用long,则该字节码不会-它会短一个字节码

然而您不能以这种方式将字节码外推到机器码中。类文件(字节码)是非常简单、完全未优化的结构,JVM只需遵循JVM规范的规则,JVM通常不指定计时和其他行为

例如,在实践中,JVM执行所有代码的速度非常慢,只是“愚蠢地”解释字节码,并浪费额外的时间和内存做一些基本的簿记,比如跟踪分支(如果
)的走向

然后,如果hotspot注意到某个方法被大量调用,它将需要一些时间,并使用该簿记来生成经过微调的机器代码。在故障案例比跳转案例快*的CPU上,它将使用该簿记来优化
if
的走向,以使更常见的案例得到故障ough。它甚至会展开循环,并进行各种令人惊讶和深远的优化。毕竟,这是代码的1%,需要99%的时间,所以花相对较长的时间来生成优化的机器代码是值得的

我甚至不知道I2L本身,即使没有热点参与,是否花费了大量的时间。这是一条完全可以在寄存器中完成的指令,它是一个单字节操作码,而且随着流水线CPU的正常工作,我打赌在绝大多数情况下,这花费了几乎0额外的时间,它悄悄地介于其他操作之间考虑到热点问题,它很可能最终被完全优化掉

因此,问题就变成了,在你的目标硬件上,你拥有的特定版本的java(从oracle的java8到OpenJ9 14,这里有很多选择,它是CPU、操作系统和JVM版本的组合爆炸),它有多“坏”

也许这是一个通用的库,而您的目标是所有这些(许多版本、许多操作系统和CPU),没有简单的答案:使用诸如在许多平台上彻底测试性能之类的工具,或者假设开销可能会影响某些奇特的组合

但是,如果您可以将JVM和arch/OS限制得更低,那么这将变得更容易——只需JMH您的目标部署,现在您就知道了

不管它值多少钱,我打赌促销活动的成本不会在这里变得足够重要(更不用说在JMH中出现了)

*)在绝大多数CPU上,唯一可用的分支指令是“如果设置了某个标志,则转到代码中的此位置”-因此要编写IF,首先要编写
GOTO a bunch ahead IF condition
,然后是
else
代码,最后是
转到IF块后的行,然后是IF代码

注意:在启动java可执行文件时,您可以使用一些
-XX
参数,让它在某个方法热点时打印出来,甚至要求它打印它生成的机器代码,然后您可以通过反汇编程序查看真正重要的代码:CPU上到底运行了什么。即使有额外的指令,也不会因为CPU流水线而花费太多


NB2:在32位体系结构上,long通常比int的成本要高出很多,但是32位体系结构在这段时间里非常少见,所以我怀疑这一点在这里很重要。

如果你想加快程序的速度,它会比int贵得多