首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

Java字节码的一段旅行经历——提升硬实力1

  • 25-03-07 19:01
  • 4645
  • 7544
blog.csdn.net

字节码指令

1.1 什么是字节码

字节码(Byte-code)是一种包含执行程序,由一序列 op 代码/数据对组成的二进制文件,是一种中间码。字节是电脑里的数据量单位。

1.2 javap 工具

自己分析类文件(字节码)太麻烦了,Oracle提供了javap工具来反编译class文件

javap -v HelloWorld.class
  1. /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/bin/javap -v com.jvm.t07_bytecode.T01_HelloWorld
  2. Classfile /Users/lei/IdeaProjects/JvmLearn/target/classes/com/jvm/t07_bytecode/T01_HelloWorld.class
  3. Last modified 2020-8-10; size 586 bytes
  4. MD5 checksum 916c3ebdbfef6b6fab63cac6a085aaa1
  5. Compiled from "T01_HelloWorld.java"
  6. public class com.jvm.t07_bytecode.T01_HelloWorld
  7. minor version: 0
  8. major version: 52
  9. flags: ACC_PUBLIC, ACC_SUPER
  10. Constant pool:
  11. #1 = Methodref #6.#20 // java/lang/Object."":()V
  12. #2 = Fieldref #21.#22 // java/lang/System.out:Ljava/io/PrintStream;
  13. #3 = String #23 // HelloWorld
  14. #4 = Methodref #24.#25 // java/io/PrintStream.println:(Ljava/lang/String;)V
  15. #5 = Class #26 // com/jvm/t07_bytecode/T01_HelloWorld
  16. #6 = Class #27 // java/lang/Object
  17. #7 = Utf8
  18. #8 = Utf8 ()V
  19. #9 = Utf8 Code
  20. #10 = Utf8 LineNumberTable
  21. #11 = Utf8 LocalVariableTable
  22. #12 = Utf8 this
  23. #13 = Utf8 Lcom/jvm/t07_bytecode/T01_HelloWorld;
  24. #14 = Utf8 main
  25. #15 = Utf8 ([Ljava/lang/String;)V
  26. #16 = Utf8 args
  27. #17 = Utf8 [Ljava/lang/String;
  28. #18 = Utf8 SourceFile
  29. #19 = Utf8 T01_HelloWorld.java
  30. #20 = NameAndType #7:#8 // "":()V
  31. #21 = Class #28 // java/lang/System
  32. #22 = NameAndType #29:#30 // out:Ljava/io/PrintStream;
  33. #23 = Utf8 HelloWorld
  34. #24 = Class #31 // java/io/PrintStream
  35. #25 = NameAndType #32:#33 // println:(Ljava/lang/String;)V
  36. #26 = Utf8 com/jvm/t07_bytecode/T01_HelloWorld
  37. #27 = Utf8 java/lang/Object
  38. #28 = Utf8 java/lang/System
  39. #29 = Utf8 out
  40. #30 = Utf8 Ljava/io/PrintStream;
  41. #31 = Utf8 java/io/PrintStream
  42. #32 = Utf8 println
  43. #33 = Utf8 (Ljava/lang/String;)V
  44. {
  45. public com.jvm.t07_bytecode.T01_HelloWorld();
  46. descriptor: ()V
  47. flags: ACC_PUBLIC
  48. Code:
  49. stack=1, locals=1, args_size=1
  50. 0: aload_0
  51. 1: invokespecial #1 // Method java/lang/Object."":()V
  52. 4: return
  53. LineNumberTable:
  54. line 11: 0
  55. LocalVariableTable:
  56. Start Length Slot Name Signature
  57. 0 5 0 this Lcom/jvm/t07_bytecode/T01_HelloWorld;
  58. public static void main(java.lang.String[]);
  59. descriptor: ([Ljava/lang/String;)V
  60. flags: ACC_PUBLIC, ACC_STATIC
  61. Code:
  62. stack=2, locals=1, args_size=1
  63. 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
  64. 3: ldc #3 // String HelloWorld
  65. 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  66. 8: return
  67. LineNumberTable:
  68. line 13: 0
  69. line 14: 8
  70. LocalVariableTable:
  71. Start Length Slot Name Signature
  72. 0 9 0 args [Ljava/lang/String;
  73. }
  74. SourceFile: "T01_HelloWorld.java"
  75. Process finished with exit code 0

2.3 图解方法执行流程

1)原始java 代码

  1. /*
  2. 演示 字节码指令 和 操作数栈、常量池的关系
  3. */
  4. public class T02_ByteCommandStackConstantPoolRel {
  5. public static void main(String[] args) {
  6. int a = 10;
  7. int b = Short.MAX_VALUE + 1;
  8. int c = a + b;
  9. System.out.println(c);
  10. }
  11. }

2)编译后的字节码文件

  1. /Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/bin/javap -v com.jvm.t07_bytecode.T02_ByteCommandStackConstantPoolRel
  2. Classfile /Users/lei/IdeaProjects/JvmLearn/target/classes/com/jvm/t07_bytecode/T02_ByteCommandStackConstantPoolRel.class
  3. Last modified 2020-8-10; size 709 bytes
  4. MD5 checksum cc8fc12b6e178b8f28e787497e993363
  5. Compiled from "T02_ByteCommandStackConstantPoolRel.java"
  6. public class com.jvm.t07_bytecode.T02_ByteCommandStackConstantPoolRel
  7. minor version: 0
  8. major version: 52
  9. flags: ACC_PUBLIC, ACC_SUPER
  10. Constant pool:
  11. #1 = Methodref #7.#25 // java/lang/Object."":()V
  12. #2 = Class #26 // java/lang/Short
  13. #3 = Integer 32768
  14. #4 = Fieldref #27.#28 // java/lang/System.out:Ljava/io/PrintStream;
  15. #5 = Methodref #29.#30 // java/io/PrintStream.println:(I)V
  16. #6 = Class #31 // com/jvm/t07_bytecode/T02_ByteCommandStackConstantPoolRel
  17. #7 = Class #32 // java/lang/Object
  18. #8 = Utf8
  19. #9 = Utf8 ()V
  20. #10 = Utf8 Code
  21. #11 = Utf8 LineNumberTable
  22. #12 = Utf8 LocalVariableTable
  23. #13 = Utf8 this
  24. #14 = Utf8 Lcom/jvm/t07_bytecode/T02_ByteCommandStackConstantPoolRel;
  25. #15 = Utf8 main
  26. #16 = Utf8 ([Ljava/lang/String;)V
  27. #17 = Utf8 args
  28. #18 = Utf8 [Ljava/lang/String;
  29. #19 = Utf8 a
  30. #20 = Utf8 I
  31. #21 = Utf8 b
  32. #22 = Utf8 c
  33. #23 = Utf8 SourceFile
  34. #24 = Utf8 T02_ByteCommandStackConstantPoolRel.java
  35. #25 = NameAndType #8:#9 // "":()V
  36. #26 = Utf8 java/lang/Short
  37. #27 = Class #33 // java/lang/System
  38. #28 = NameAndType #34:#35 // out:Ljava/io/PrintStream;
  39. #29 = Class #36 // java/io/PrintStream
  40. #30 = NameAndType #37:#38 // println:(I)V
  41. #31 = Utf8 com/jvm/t07_bytecode/T02_ByteCommandStackConstantPoolRel
  42. #32 = Utf8 java/lang/Object
  43. #33 = Utf8 java/lang/System
  44. #34 = Utf8 out
  45. #35 = Utf8 Ljava/io/PrintStream;
  46. #36 = Utf8 java/io/PrintStream
  47. #37 = Utf8 println
  48. #38 = Utf8 (I)V
  49. {
  50. public com.jvm.t07_bytecode.T02_ByteCommandStackConstantPoolRel();
  51. descriptor: ()V
  52. flags: ACC_PUBLIC
  53. Code:
  54. stack=1, locals=1, args_size=1
  55. 0: aload_0
  56. 1: invokespecial #1 // Method java/lang/Object."":()V
  57. 4: return
  58. LineNumberTable:
  59. line 15: 0
  60. LocalVariableTable:
  61. Start Length Slot Name Signature
  62. 0 5 0 this Lcom/jvm/t07_bytecode/T02_ByteCommandStackConstantPoolRel;
  63. public static void main(java.lang.String[]);
  64. descriptor: ([Ljava/lang/String;)V
  65. flags: ACC_PUBLIC, ACC_STATIC
  66. Code:
  67. stack=2, locals=4, args_size=1
  68. 0: bipush 10
  69. 2: istore_1
  70. 3: ldc #3 // int 32768
  71. 5: istore_2
  72. 6: iload_1
  73. 7: iload_2
  74. 8: iadd
  75. 9: istore_3
  76. 10: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
  77. 13: iload_3
  78. 14: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
  79. 17: return
  80. LineNumberTable:
  81. line 17: 0
  82. line 18: 3
  83. line 19: 6
  84. line 20: 10
  85. line 21: 17
  86. LocalVariableTable:
  87. Start Length Slot Name Signature
  88. 0 18 0 args [Ljava/lang/String;
  89. 3 15 1 a I
  90. 6 12 2 b I
  91. 10 8 3 c I
  92. }
  93. SourceFile: "T02_ByteCommandStackConstantPoolRel.java"
  94. Process finished with exit code 0

3)常量池载入运行时常量池

4)方法字节码载入方法区

5)main线程开始运行,分配栈帧内存

(stack=2,  locals=4)

  

6)执行引擎开始执行字节码

bipush 10

  • 将一个byte压入操作数栈(其长度会补齐4个字节),类似的指令还有
  • sipush将一个short压入操作数栈(其长度会补齐4个字节)
  • idc将一个int压入操作数栈
  • idc2_w将一个long压入操作数栈(分两次压入,因为long是8个字节)
  • 这里小的数字都是和字节码指令存在一起,超过short范围的数字存入常量池

istore_1

  • 将操作数栈顶数据弹出,存入局部变量表的槽位slot 1中,下图的args/a/b/c就是对应的槽位

idc  #3

  • idc 从常量池加载 #3 数据到操作数栈
  • 注意: Short.MAX_VALUE是32767,所以32768 = Short.MAX_VALUE + 1 超过了Short.MAX_VALUE的值,所以编译器将其放在运行时常量池中。实际是在编译期间计算好的,是一种优化,叫常量折叠优化

istore_2

  • 将操作数栈顶数据弹出,存入局部变量表的2号槽位中

iload_1

再接下来,需要执行int c = a + b;执行引擎不能直接在局部变量表进行a+b操作,需要先将a、b进行读取,然后放入操作数栈中才能进行计算分析

  • 把局部变量从1号槽位加载数据到操作数栈中

iload 2

  • 再把局部变量从2号槽位加载数据到操作数栈中

iadd

  • iadd会弹出操作数栈中的2个变量,并进行求和得到32778,最后将结果32778写回到操作数栈中


istore_3

  • 将操作数栈的数弹出,存入局部变量表3号槽位。到目前为止,局部变量a、b、c都有值了

getstatic #4

  • 去常量池找到成员变量引用,去堆中找到System.out对象。getstatic 会把对象引用放入操作数栈中

iload_3

  • 将局部变量表3号槽位的值加载到操作数栈中

invokevirtual #5

  • 找到常量池 #5项
  • 定位到方法区 java/io/PrintStream.println: (I)V方法
  • 生成新的栈帧(分配locals、stack等)
  • 传递传数,执行新栈帧中的字节码

  • 执行完毕,弹出栈帧
  • 清除main操作数栈内容

return

  • 完成main方法调用,弹出main栈帧
  • 程序结束

文章最后,给大家推荐一些受欢迎的技术博客链接:

  1. Hadoop相关技术博客链接
  2. Spark 核心技术链接
  3. JAVA相关的深度技术博客链接
  4. 超全干货--Flink思维导图,花了3周左右编写、校对
  5. 深入JAVA 的JVM核心原理解决线上各种故障【附案例】
  6. 请谈谈你对volatile的理解?--最近小李子与面试官的一场“硬核较量”
  7. 聊聊RPC通信,经常被问到的一道面试题。源码+笔记,包懂

 


欢迎扫描下方的二维码或 搜索 公众号“10点进修”,我们会有更多、且及时的资料推送给您,欢迎多多交流!

                                           

       

 

 

注:本文转载自blog.csdn.net的不埋雷的探长的文章"https://blog.csdn.net/weixin_32265569/article/details/107904061"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top