79 | 程序员练级攻略(2018):Java底层知识

79 | 程序员练级攻略(2018):Java底层知识

朗读人:柴巍    07′25′′ | 3.40M

前两篇文章分享的是系统底层方面的内容,今天我们进入高手成长篇的第二部分——Java 底层知识。

Java 字节码相关

首先,Java 最黑科技的玩法就是字节码编程,也就是动态修改或是动态生成 Java 字节码。Java 的字节码相当于汇编,其中的一些细节你可以从下面的这几个教程中学习。

当然,一般来说,我们不使用 JVMTI 操作字节码,而是用一些更好用的库。这里有三个库可以帮你比较容易地做这个事。

  • asmtools - 用于生产环境的 Java .class 文件开发工具。
  • Byte Buddy - 代码生成库:运行时创建 Class 文件而不需要编译器帮助。
  • Jitescript - 和 BiteScript 类似的字节码生成库。

就我而言,我更喜欢 Byte Buddy,它在 2015 年还获了 Oracle 的 “Duke’s Choice” 大奖,其中说 Byte Buddy 极大地发展了 Java 的技术。

使用字节码编程可以玩出很多高级玩法,最高级的还是在 Java 程序运行时进行字节码修改和代码注入。听起来是不是一些很黑客,也很黑科技的事?是的,这个方式使用 Java 这门静态语言在运行时可以进行各种动态的代码修改,而且可以进行无侵入的编程。

比如, 我们不需要在代码中埋点做统计或监控,可以使用这种技术把我们的监控代码直接以字节码的方式注入到别人的代码中,从而实现对实际程序运行情况进行统计和监控。如果你看过我的《编程范式游记》,你就知道这种技术的威力了,其可以很魔法地把业务逻辑和代码控制分离开来。

要做到这个事,你还需要学习一个叫 Java Agent 的技术。Java Agent 使用的是 “Java Instrumentation API”,其主要方法是实现一个叫 premain() 的方法(嗯,一个比 main() 函数还要超前执行的 main 函数),然后把你的代码编译成一个 jar 文件。

在 JVM 启动时,使用这样的命令行来引入你的 jar 文件:java -javaagent:yourAwesomeAgent.jar -jar App.jar。更为详细的文章你可以参看:“Java Code Geeks: Java Agents”,你还可以看一下这个示例项目:jvm-monitoring-agent 或是 EntryPointKR/Agent.java。如果想用 ByteBuddy 来玩,你可以看看这篇文章 “通过使用 Byte Buddy,便捷地创建 Java Agent”。如果你想学习如何用 Java Agent 做监控,你可以看一下这个项目 Stage Monitor

JVM 相关

接下来讲讲 Java 底层知识中另一个非常重要的内容——JVM。

说起 JVM,你有必要读一下 JVM 的规格说明书,我在这里放一个 Java 8 的, The Java Virtual Machine Specification Java SE 8 Edition 。对于规格说明书的阅读,我认为是系统了解 JVM 规范的最佳文档,这个文档可以让你对于搞不清楚或是诡异的问题恍然大悟。关于中文翻译,有人在 GitHub 上开了个 Repo - “java-virtual-machine-specification”。

另外,也推荐一下 JVM Anatomy Park JVM 解剖公园,这是一个系列的文章,每篇文章都不长,但是都很精彩,带你一点一点地把 JVM 中的一些技术解开。

学习 Java 底层原理还有 Java 的内存模型,官方文章是 JSR 133。还有马里兰大学的威廉·皮尤(William Pugh)教授收集的和 Java 内存模型相关的文献 - The Java Memory Model ,你可以前往浏览。

对于内存方面,道格·利(Doug Lea)有两篇文章也是很有价值的。

  • The JSR-133 Cookbook for Compiler Writers,解释了怎样实现 Java 内存模型,特别是在考虑到多处理器(或多核)系统的情况下,多线程和读写屏障的实现。

  • Using JDK 9 Memory Order Modes,讲了怎样通过 VarHandle 来使用 plain、opaque、release/acquire 和 volatile 四种共享内存的访问模式,并剖析了底层的原理。

垃圾回收机制也是需要好好学习的,在这里推荐一本书 《The Garbage Collection Handbook》,在豆瓣上的得分居然是 9.9(当然,评价人数不多)。这本书非常全面地介绍了垃圾收集的原理、设计和算法。但是这本书也是相当难啃的。中文翻译《垃圾回收算法手册》翻译得很一般,有人说翻译得很烂。所以,如果可能,还是读英文版的。如果你对从事垃圾回收相关的工作有兴趣,那么你需要好好看一下这本书。

当然,更多的人可能只需要知道怎么调优垃圾回收, 那么推荐读读 Garbage Collection Tuning Guide ,它是 Hotspot Java 虚拟机的垃圾回收调优指南,对你很有帮助。

Quick Tips for Fast Code on the JVM 也是一篇很不错的文章,里面有写出更快的 Java 代码的几个小提示,值得一读。

小结

好了,总结一下今天学到的内容。Java 最黑科技的玩法就是字节码编程,也就是动态修改或是动态生成 Java 字节码。Java 的字节码相当于汇编,学习其中的细节很有意思,为此我精心挑选了 3 篇文章,供你学习。我们一般不使用 JVMTI 操作字节码,而是用一些更好用的库,如 asmtools、Byte Buddy 和 BiteScript 等。使用字节码编程可以玩出很多高级玩法,其中最高级的玩法是在 Java 程序运行时进行字节码修改和代码注入。同时,我介绍了 Java Agent 技术,帮助你更好地实现这种高级玩法。

JVM 也是学习 Java 过程中非常重要的一部分内容。我推荐阅读一下 JVM 的规格说明书,我认为,它是系统了解 JVM 规范的最佳文档,可以让你对于搞不清楚或是诡异的问题恍然大悟。同时推荐了 JVM Anatomy Park 系列文章,也非常值得一读。

随后介绍的是 Java 的内存模型和垃圾回收机制,尤其给出了如何调优垃圾回收方面的资料。这些内容都很底层,但也都很重要。对于想成为高手的你来说,还是有必要花时间来啃一啃的。

下篇文章是数据库方面的内容,我们将探讨各种类型的数据库,非常有意思。敬请期待。

下面是《程序员练级攻略(2018)》系列文章的目录。

版权归极客邦科技所有,未经许可不得转载

精选留言

  • javaee
    有同学认为这种介绍文章没用,一大堆引用。我觉得吧,这文章价值很大。如果只是要写一篇关于字节码或JVM的详细使用,那很多书籍或网站可能有了,反而不值得写。耗子叔这系列文章,在我看来很有大局观,自顶向下梳理了各种技术脉络。授人以渔其实更重要,好的老师是给你指出明路,让你少走弯路,而不是给你讲解几道题。不过这也许要工作几年后才能更深刻的体会到吧,这些总结的资源是一笔财富,至少不用走弯路,可以有选择性的去挑选适合你的认为有价值有兴趣的内容去学习。
    2018-07-19
    作者回复

    谢谢理解

    2018-07-21

  • 怪盗キッド
    Hi,我利用ASM写了一个简单、快速且无侵入的Java方法监控工具MyPerf4J,通过JavaAgent方式对Java方法进行字节码注入,可以统计出方法的执行性能指标,包括RPS、Avg、TP50、TP90、TP99、TP999等,Github地址:https://github.com/ThinkpadNC5/MyPerf4J
    2018-07-03
    作者回复

    👍那些统计,你用到了蓄水池算法了吗?

    2018-07-03

  • superryanguo
    java有必要单独抽一篇来讲吗?而且都是引用
    2018-07-03
  • ruby
    皓哥,后面有大数据文章,怎么学spark.hadoop等吗?
    2018-07-03
  • 吃桔子的攻城狮
    第一次评论。这个专栏看了这么久,第一次觉得有必要说几句,这种风格的专栏真的非常赞。看到有些同学说链接太多缺少耗子哥自己的东西,我想说这个系列随便一篇文章拿出来,如果纯自己写都能单独写成一个系列甚至一本书。这就像重复造轮子,明明已经有了优秀的文献资料,为什么要重新写一套?相反,能把这些优质资源做整合,串联,归纳,提供学习的路径和思路才是受益无穷的!

    有同学说这些都是网上可以找到的,那不妨请想一下,如果只给你本系列某篇文章的题目,凭自己你真的可以找得到这些资料吗?不会陷入现在互相抄来抄去的劣质博客里迷惘困惑,百思不得其解吗?

    支持这种风格,我认为订阅专栏的钱花的很超值!
    2018-08-03
    作者回复

    谢谢

    2018-08-03

  • 墨梵
    耗叔有专门讲c++对象模型方面和内存分配的篇章嚒?
    2018-07-04
  • 鹤鸣
    C++程序员问个问题:怎样对一个已有的基于spring的项目优化性能?目前我这边首先要做的事情是测试出性能瓶颈,但是目前为止我还在使用那种很土的办法,纯体力活的那种,我觉得这个路子不大对头。
    2018-07-04
  • Rolin
    Android 程序猿好好学!
    2018-07-03
  • 葛阳阳
    2018-07-03
  • Tony
    耗子哥,我记得你以前写过一篇关于java进阶的比较全面的文章,怎么找不到了?
    2018-07-12
  • 付彬
    2018-07-04
  • LenX
    动态生成的代码 debug 起来挺费劲的,尤其是用 IDE。耗叔有什么工具或方法推荐吗?
    2018-07-03
  • 怪盗キッド
    没有使用蓄水池算法,我是通过数组+Map的方式存储数据:
    对于数组来说,下标代表方法的响应时间,下标对应的值代表该响应时间的数量;
    对于Map来说,Key代表方法的响应时间,Value代表该响应时间的数量;(Accurate模式)
    2018-07-03
  • ZYCHD(子玉)
    读耗子书的文章总给人带来新鲜的感觉。视野很开阔。前后穿插纵横千里!
    2018-07-03