【问题标题】:Finding the Bytecode Size of a Java Method查找 Java 方法的字节码大小
【发布时间】:2014-02-16 22:03:29
【问题描述】:

我正在尝试计算方法的字节码大小,因为我想确保它足够小,可以通过编译器优化进行内联。

我看到内联方法的默认最大大小是 35,所以如果方法大于此,我将修改代码或将其分解为多个方法。

我有一个方法可以生成下面的字节码(通过 IntelliJ IDEA 的 ASM Bytecode Outline 插件反汇编)。

我如何知道该方法的字节码大小? LINENUMBER 似乎引用了原始源代码的行号。

public static mergeNativeArrays([Ljava/lang/Object;[Ljava/lang/Object;IZ)[Ljava/lang/Object;
 L0
  LINENUMBER 865 L0
  ALOAD 0
  ASTORE 4
 L1
  LINENUMBER 867 L1
  ILOAD 2
  IFGE L2
 L3
  LINENUMBER 868 L3
  ALOAD 0
  ARRAYLENGTH
  ISTORE 2
 L2
  LINENUMBER 870 L2
 FRAME APPEND [[Ljava/lang/Object;]
  ILOAD 2
  ALOAD 1
  ARRAYLENGTH
  IADD
  ISTORE 5
 L4
  LINENUMBER 872 L4
  ALOAD 4
  ARRAYLENGTH
  ILOAD 5
  IF_ICMPGE L5
 L6
  LINENUMBER 874 L6
  ILOAD 3
  IFEQ L7
 L8
  LINENUMBER 875 L8
  ILOAD 5
  INVOKESTATIC railo/commons/math/MathUtil.nextPowerOf2 (I)I
  ISTORE 5
 L7
  LINENUMBER 877 L7
 FRAME APPEND [I]
  ILOAD 5
  ANEWARRAY java/lang/Object
  ASTORE 4
 L9
  LINENUMBER 878 L9
  ALOAD 0
  ICONST_0
  ALOAD 4
  ICONST_0
  ALOAD 0
  ARRAYLENGTH
  INVOKESTATIC java/lang/System.arraycopy (Ljava/lang/Object;ILjava/lang/Object;II)V
 L5
  LINENUMBER 881 L5
 FRAME SAME
  ALOAD 1
  ICONST_0
  ALOAD 4
  ILOAD 2
  ALOAD 1
  ARRAYLENGTH
  INVOKESTATIC java/lang/System.arraycopy (Ljava/lang/Object;ILjava/lang/Object;II)V
 L10
  LINENUMBER 883 L10
  ALOAD 4
  ARETURN
 L11
  LOCALVARIABLE dst [Ljava/lang/Object; L0 L11 0
  LOCALVARIABLE src [Ljava/lang/Object; L0 L11 1
  LOCALVARIABLE dstPosition I L0 L11 2
  LOCALVARIABLE doPowerOf2 Z L0 L11 3
  LOCALVARIABLE result [Ljava/lang/Object; L1 L11 4
  LOCALVARIABLE newSize I L4 L11 5
  MAXSTACK = 5
  MAXLOCALS = 6

【问题讨论】:

  • 对不起,我的意思是内联。您可以使用 -XX:+PrintInlining 标志。
  • 35 字节是不常用方法的默认最大值,如果您经常调用这些方法,则可以内联更大的方法(常用方法的默认值取决于 JVM)。您可以随时增加此数字以查看它提高了代码的性能。
  • 我建议使用 javap。
  • 确保代码已预热将使性能提高 10-100 倍,远远超过单独的内联。如果您不能确定代码是否已预热,我会采取措施确保关键代码被调用得足够多。
  • 让从未被称为更高效的代码有什么意义。除非您清楚地了解您要优化的内容以及显示您所做更改的指标,否则您会迷失方向。你同样有可能让事情变得更糟、更复杂。

标签: java bytecode compiler-optimization java-bytecode-asm


【解决方案1】:

我如何知道该方法的字节码大小?

一种方法是将它们相加:-)

每条字节码指令由 1 个主指令字节加上固定数量的操作数字节组成。


更实用的方法是使用javap -c 转储包含字节码的类文件。输出包括每条指令的字节偏移量。

参考:http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javap.html


1) 我可以将 ALOAD 0 ASTORE 4 添加为 4 个字节,但我该如何处理 ARRAYLENGTH 或 INVOKESTATIC 方法名?

指令列在 JVM 规范的第 6.5 节 - http://docs.oracle.com/javase/specs/jvms/se7/html/index.html

  1. 向下滚动到索引的相关部分。
  2. 点击说明链接。
  3. 阅读“格式”和“描述”以确定使用了多少字节。

按照这个过程,我推断出 ARRAYLENGTH 是 1 个字节,而 INVOKESTATIC 是 3 个字节。

2) 我尝试使用 javap,但由于某种原因找不到类(它在 jar 中,我将 -classpath filename.jar 传递给 javap 但它不起作用)。

再次阅读javap 手册条目。如果你正确使用它确实工作。 (也许您没有以正确的格式提供完全限定的类名。)

【讨论】:

  • 这就是我想要做的,但是 1) 我可以将 ALOAD 0 ASORE 4 添加为 4 个字节,但是我该如何处理 ARRAYLENGTH 或 INVOKESTATIC 方法名? 2)我尝试使用 javap 但由于某种原因我找不到类(它在一个 jar 中,我将 -classpath filename.jar 传递给 javap 但它不起作用)
  • 你说得对,我忘记了该类的打包方式使其对 jar “不可见”,以便在运行时进行更新。我 javap 工作,方法显示 [64: areturn] 所以我猜这意味着它有 65 个字节长?
  • 听起来不错。如果您不相信答案,请通过手动计算方法大小进行交叉检查。
  • 我不确定是否可以手动添加它们,因为 [ALOAD 0] 建议 2 个字节,而真正的指令是 [aload_0] 1 个字节。我确实相信 javap 输出,并纠正我之前的评论——javap“位置”输出是基于 0 的,所以当它显示 [64: areturn] 时,它实际上是 64 个字节,包括 [areturn] 指令。感谢您的洞察力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-03
  • 1970-01-01
  • 2020-07-13
相关资源
最近更新 更多