当前位置: 首页 > news >正文

理解JVM字节码,做点有意的事儿

作者:侯树成

来源:Tomcat那些事儿

 

JVM 字节码,做为虚拟机执行的指令,对于平时做 Java 应用开发来说,一直像蒙着一层神秘面纱,朦朦胧胧。

 

但其实理解了字节码指令,对于 Java 虚拟机的工作原理,对于基于「栈」的指令执行,对于一些 JVM 的新特性、语法都能更好的理解本质。

 

一般英文文章中介绍一些深入底层原理的时候,都喜欢用这个词:「under the hood」,本意是指汽车等引擎盖下,后来引申为一些底层原理。

 

什么是字节码?

Java 虚拟机的指令由一个字节长度的操作码(opcode)和紧随其后的可选的操作数(operand)构成,如下所示。

<opcode> [<operand1>, <operand2>]

比如将整型常量 100 压栈到栈顶的指令是 bipush 100,其中 bipush 是操作码,100 是操作数。字节码(bytecode)名字的由来是操作码的长度用一个字节表示。因为操作码长度只有一个字节长度,这使得编译后的字节码文件非常小巧紧凑,但也直接限制整个 JVM 操作码指令集的数量最多只能有 256 个,目前已经使用超过了 200 个。

 

大部分字节码指令是与类型相关的,比如 ireturn 指令用于返回一个 int 类型的数据,dreturn 指令用于返回一个 double 类型的数据,freturn 指令用于返回一个 float 类型的数据,这也使得字节码实际的指令类型远小于 200 个。

 

字节码使用大端序(Big-Endian)表示,即高位在前,低位在后的方式,比如字节码getfield 00 02,表示的是 getfiled 0x00<<8 | 0x02(getfield #2)。

 

字节码并不是某种虚拟 CPU 的机器码,而是一种介于源码和机器码中间的一种抽象表示方法,不过字节码通过 JIT(Just In Time)技术可以被进一步编译成机器码。

 

根据字节码的不同用途,字节码指令可以大概分为如下几类:

  • 加载和存储指令,比如 iload 将一个整型值从局部变量表加载到操作数栈; 

  • 控制转移指令,比如条件分支 ifeq;

  • 对象操作,比如创建类实例的指令 new;

  • 方法调用,比如 invokevirtual 指令用于调用对象的实例方法;

  • 运算指令和类型转换,比如加法指令 iadd;

  • 线程同步,比如monitorenter 和 monitorexit 这两条指令用于支持 synchronized 关键字的语义;

  • 异常处理,比如 athrow 显式抛出异常。

 

字节码是运行在 JVM 上的,为了能弄懂字节码,需要对 JVM 的运行原理有所了解。

 

而掀开JVM的盖,字节码指令也可以说是很重要的一部分了。理解了它,对于一些 ORM 框架等做的编译时的(Enhance)字节码增强,你就能知道他到底干了什么。

 

理解了字节码指令之后,可能就会抱怨其使用的繁琐。而ASM、Javassist 等工具就是免去你重新搬砖盖房子的,直接以更方便的API提供给用户,免除了手工解析的苦恼。

 

理解和掌握了 JVM 字节码,除了偶尔编辑和分析一下 class 文件,少数情况下通过ASM等增加或修改些指令外,其实还能做不少有意思的事儿。像类的加载时增强,Agent attach、Instrument实现类的 transform,运行时的retransform等...

 

如果想对JVM有更深次的理解,推荐阅读:《深入理解 JVM字节码》,本书分为字节码原理篇和应用篇。

第一部分是关于 class 文件的结构、字节码的工作原理、 Javac的编译原理,以及 ASM、Javassist工具的使用做了细致的介绍。此外还包含对于 Java Instrumentation 的原理,Lombok 这种 JSR 269的插件化注解的处理原理等也有介绍。

第二部分介绍了一些比较有意思的实战思路和尝试。像字节码在 Dubbo 通过Javassist实现动态代理的应用 、在 JaCoCo中对于代码覆盖率的实现。如果这些你觉得老生常谈,那软件的破解和防破解可能会让你耳目一新。

我们知道 Java 的 class 虽然经过了编译,但通过反编译工具可以轻松的查看源码,甚至不差分毫。所以书里对于破解提到了直接修改class 文件和通过 Java agent 的无痛破解两种方式。所以对于Java 应用,通过反编译能很快的了解到软件的实现思路,甚至对于商业软件会面临盗版、破解的风险。

不知攻怎么知道防,理解了破解的方式,对于书中介绍的混淆和通过自定义类加载器来加载加密的 class文件防,都是不错的思路。

另外,现在分布式应用、微服务系统越来越流行,给对应的分析和监控带来了不小的挑战,书中全链路分布式跟踪、通过ASM 操作字节码,实现 APM 工具,进行应用的性能分析、诊断等,都有借鉴意义。

 

 

本书正在参加当当网开学季大促,每满100-50的基础上,满200元再叠加立减40元!下单输入优惠码【EWAVRU】即可立减

点击链接了解详情并购买 

更多精彩回顾

书讯 |华章计算机拍了拍你,并送来了8月书单(下)

书讯 | 华章计算机拍了拍你,并送来了8月书单(上)

上新 | 首本深入讲解Linux内核观测技术BPF的书上市!
书单 | 《天才引导的历程》| 西安交通大学送给准大一新生的礼物

干货 | 机器人干活,我坐一边喝茶——聊聊最近爆火的RPA

收藏 | 揭秘阿里巴巴的客群画像

点击阅读全文购买

相关文章:

  • 平安科技王健宗:所有 AI 前沿技术,都可以在联邦学习中大展身手!
  • 终于有人把AI、BI、大数据、数据科学讲明白了
  • 从被动到主动,换个角度看DB
  • 【第19期】追MM的各种算法
  • 巨详细!使用OpenCV和OpenVINO轻松创建深度学习应用
  • 9月书讯(上)| 开学季,读新书
  • 一本书带你吃透Nginx应用与运维
  • 开学季——计算机专业学生必读的10本畅销经典
  • 9月书讯(下)| 开学季,读新书
  • 交互设计是什么?
  • 开学季——想打好数学基础?这些经典教材你最需要!
  • Java 二十五载,正在 Kotlin 化!
  • 开学季 | 用十本书打破固有思维,“文理兼修”
  • 云安全调查:过去一年半80%的企业遭受云数据泄露
  • DB-Engines 9月数据库排名:ClickHouse一路猛冲,Redis坐稳第七
  • [Vue CLI 3] 配置解析之 css.extract
  • 《Java编程思想》读书笔记-对象导论
  • 【comparator, comparable】小总结
  • 2017-09-12 前端日报
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • create-react-app做的留言板
  • ES6 学习笔记(一)let,const和解构赋值
  • express.js的介绍及使用
  • Fastjson的基本使用方法大全
  • Github访问慢解决办法
  • Java读取Properties文件的六种方法
  • Joomla 2.x, 3.x useful code cheatsheet
  • ​iOS安全加固方法及实现
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #QT(一种朴素的计算器实现方法)
  • (C#)一个最简单的链表类
  • (C++20) consteval立即函数
  • (C语言)字符分类函数
  • (javascript)再说document.body.scrollTop的使用问题
  • (办公)springboot配置aop处理请求.
  • (定时器/计数器)中断系统(详解与使用)
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (三)c52学习之旅-点亮LED灯
  • (算法)求1到1亿间的质数或素数
  • (转载)PyTorch代码规范最佳实践和样式指南
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • .Net mvc总结
  • .net图片验证码生成、点击刷新及验证输入是否正确
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • @RunWith注解作用
  • [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞 S2-005 (CVE-2010-1870)
  • [AHOI2009]中国象棋 DP,递推,组合数
  • [AMQP Connection 127.0.0.1:5672] An unexpected connection driver error occured
  • [C++] 默认构造函数、参数化构造函数、拷贝构造函数、移动构造函数及其使用案例
  • [C++]AVL树怎么转
  • [CSS] 点击事件触发的动画
  • [C语言][PTA基础C基础题目集] strtok 函数的理解与应用
  • [iphone-cocos2d]关于Loading的若干处理和讨论
  • [Mvc]在ASP.NET MVC中使用Repeater