云时代的 JVM 原理与实战
康杨
京东资深架构师
3111 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 39 讲
云时代的 JVM 原理与实战
15
15
1.0x
00:00/00:00
登录|注册

01|重识JVM:JVM的起源、特性与系统构成

你好,我是康杨。欢迎你加入学习,和我一起开启 JVM 的探索之旅。
作为这门课程的第一讲,我希望通过我的介绍,能让你对 JVM 有一个整体的认知。我将从 JVM 的起源、它的基本特性、内部构成,以及它与我们常说的 JDK、JRE 的关系等多个维度展开,让你知其然并知其所以然。

JVM 的起源

区别于很多课程以“hello world”  开篇,我们今天从一个实际的需求开始。假设你是一家餐厅的老板,需要计算过去一周的营收总和,过去一周每天的营收分别是 102、230、320、431、130。假如你生活在公元前,这时候你可能就需要用结绳记事的方式来进行计算。
而如果你生活在 19 世纪 50 年代,那么恭喜你,你可以用计算机帮你计算了。幸亏有了计算机,不然,如果要算一年的营收,不知道要用掉多少根绳子,算多长时间呢。
当然,现在的你,显然会用更简单的方式得到结果,通过下面这段代码,JVM 就会帮你完成运算,你甚至不用考虑是在 Windows 上运行,还是在苹果电脑上运行,因为 JVM 会帮你搞定。
int[] arr = { 102230320431130};
int sum = 0;
for(int i: arr){
sum += i;
}
System.out.println("Sum is: " + sum);
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

JVM的起源可以追溯到人类计算工具的演进,从结绳记事到现代计算机,再到Java虚拟机(JVM)。JVM作为一种虚拟计算机,接收字节码并将其转化为可执行代码,实现了Java程序的平台无关性。文章介绍了JVM的基本特性,包括平台独立性、自动内存管理、高效的即时编译和强大的监控调试工具。同时,强调了深入了解JVM的重要性,以避免程序运行结果与预期不符。此外,文章还深入探讨了JVM的内部构成,包括类加载子系统、字节码执行引擎和运行时数据区。通过对JVM的全面了解,读者可以更好地理解JVM的本质和特性,提高Java编程效率。文章还介绍了JVM、JDK和JRE的关系,以及对代码进行优化的思考题。整体而言,本文全面介绍了JVM的重要性和内部机制,对于Java开发者和对JVM感兴趣的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《云时代的 JVM 原理与实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(13)

  • 最新
  • 精选
  • “相对于普通计算机基于寄存器的架构,JVM 是基于栈的虚拟机,正是因为基于栈的特性,使 JVM 具备了平台无关性”,基于栈的特性是什么意思,什么叫基于栈?可以展开说一下吗?为什么基于栈的特性就能平台无关了?

    作者回复: 基于栈的特性指的是JVM使用栈来进行计算和内存管理。在JVM中,每个线程都有一个私有的栈,用来存储方法的局部变量、方法的参数、返回值以及方法调用时的临时数据。每当线程调用一个方法时,JVM会为该方法分配一个栈帧,栈帧包含了方法的局部变量表、操作数栈等信息。与之相对,基于寄存器的架构(如普通计算机)使用寄存器来存储数据。寄存器是位于处理器内部的高速存储器,用于存放指令操作数和中间结果。基于寄存器的架构直接利用处理器的寄存器进行计算,速度较快。 基于栈的特性使JVM具备了平台无关性,主要有以下几点原因: 1. 栈的操作是在内存中进行的,并不依赖于特定的硬件架构。JVM通过使用栈来进行计算,抽象了底层的硬件细节,使得Java程序可以在不同的硬件平台上运行,而不需要修改源代码。 2. Java的字节码是面向栈的指令集。Java源码在经过编译后会生成字节码,字节码是一种中间代码,使用栈来进行操作。这些字节码可以被JVM解释执行或者编译成特定硬件架构的机器码,实现了平台无关性。 3. JVM的内存管理也是基于栈的。JVM使用栈来进行方法调用和局部变量的管理,同时也使用栈来进行内存的分配和销毁。这种基于栈的内存管理方式,简化了开发者的内存管理工作,提供了跨平台的内存管理机制。

    2023-08-23归属地:辽宁
    4
    9
  • seker
    文稿中的代码,如果thread1先执行完,那么程序会正常输出1。如果是thread2先执行完,那么程序没有任何输出。由于引入多线程,导致线程执行先后顺序不确定出现上述问题。 从程序的意图看是想thread1先写,thread2再读,那么修改start()、join()顺序就可以避免问题。即修改为: thread1.start(); thread1.join(); thread2.start(); thread2.join(); 但如果是writer()和reader()都有多个线程进入,那就是另外的解决方案了。 所以还是想问老师那段代码的意图是什么?

    作者回复: 很好的问题,通过这个问题,我并不是希望你能马上得到一个答案,而是希望引导大家去思考,一段代码从我们写出来,到真正执行环节,还有谁来谁来参与,并带来了那些影响,比如编译器重排、内存重排、指令重排这些,答案本身并不重要,引导大家去思考背后的原因,我理解才是更重要的

    2023-08-25归属地:广东
    1
  • Johar
    请教一下加载的class文件什么时候会卸载?

    作者回复: 在Java中,class文件的卸载是由Java虚拟机的垃圾回收机制决定的。一般来说,当一个类不再被任何活动的线程所引用时,它就变得可被卸载的。 具体而言,下面是导致class文件卸载的一些常见情况: 1. 类的实例被垃圾回收:当一个类的所有实例都被垃圾回收器回收时,该类就变得没有被引用,可以被卸载。 2. 类的ClassLoader被回收:当一个类的ClassLoader被垃圾回收器回收时,该类及其相关的类也会被卸载。 3. 类的引用被解除:当一个类的所有引用被解除,例如通过反射调用`Class.forName()`加载的类,在不再需要时可以手动调用`Class.forName("className").getClassLoader().clearAssertionStatus()`来解除对类的引用,从而使得该类可以被卸载。 但是并不是所有的class文件都可以被卸载。因为在Java虚拟机规范中,并没有明确要求虚拟机必须卸载类,类的卸载是可选的。一些Java虚拟机实现可能会选择不进行类的卸载,或者仅在特定条件下才进行卸载。因此,class文件的卸载行为可能会因不同的Java虚拟机实现而有所不同。

    2023-08-21归属地:重庆
    1
  • seker
    JVM 和普通计算机的关系是什么? 这里的普通计算机我理解就是物理机,是一种硬件。JVM终究是一个软件,不过可以进行内存管理、线程管理。在JVM之上可以运行Java应用程序,以及其它可以编译为字节码的编程语言。因此我觉得JVM更像是一个虚拟的操作系统,而Java应用程序则运行在这个虚拟的操作系统之上。 没有硬件作为支撑,那么软件将无法运行。因此软件对硬件是有依赖关系的。

    作者回复: 这样理解没有问题,但是整篇教程我想表达的是另外一种思考。建议再仔细品味下第一篇,去思考下计算机又是什么,他的图灵机本质,换个视角来看待这个问题,有个小提示,一切的本源是为了解决计算的问题,而解决这个问题有两个方向,一个偏重于是什么,就是阿隆佐.邱奇的lambda(λ),一个是图灵的图灵机,推荐读一下http://www.yinwang.org/blog-cn/2013/07/13/church-turing,深刻理解这个问题,会对你理解函数式编程,并发的本质,java和go的区别都很有助益的,我也会在后面第四篇重点介绍下这部分

    2023-08-25归属地:广东
  • 临风
    问题1:对于这段代码,存在两个问题。 1.join的作用是等待线程执行结束,再继续往后执行,但thread2已经start了,所以我们没办法保证thread1和thread2谁先执行,flag显然是不能保证代码执行的先后顺序的,可以通过信号量或者CountDownLatch来解决(暂时只想到了这两个,不知道还有没用别的更好的方式)。 2.变量a缺乏volatile修饰,两个可能线程会读取各自线程中的值,导致reader执行的时候取的还是0。 问题2: jvm就是对操作系统和硬件资源的抽象封装,让你无需考虑是x86还是arm的CPU,也不用管是window是还是Linux的操作系统,实现了一次编译到处运行。本质就是让你只关注自己的代码逻辑,而不用考虑底层硬件和操作系统的区别,但实际上这些事情还是得有人做的,只不过是jvm替你做了,这也就导致了一定程度上的性能损耗。但云原生时代的到了,docker的普及,因为已经对运行环境做了一层封装,大家都是执行镜像,导致Java的优势也就荡然无存了,反而因为其需要支持运行时的问题,启动服务缓慢,无法实现秒级的扩缩容而举步维艰。这些就是我的一些浅薄的认识,希望之后跟着老师能加深对云原生时代Java的理解。 附问题1的代码: public class Demo { private volatile int a = 0; private final Semaphore semaphore = new Semaphore(1); public void writer() { a = 1; semaphore.release(); } public void reader() { try { semaphore.acquire(); } catch (InterruptedException e) { throw new RuntimeException(e); } int i = a * a; System.out.println(i); } public static void main(String[] args) throws InterruptedException { final Demo example = new Demo(); Thread thread1 = new Thread(() -> example.writer()); Thread thread2 = new Thread(() -> example.reader()); thread1.start(); thread2.start(); thread1.join(); thread2.join(); } }

    作者回复: 你的思考很赞,其实通过这个例子我是想让大家去思考我们写的代码,在真正执行的时候还有谁参与,如何参与,背后原理是什么,去有整体化的思考,这样才能更好地看清楚未来的变化

    2023-08-23归属地:广东
  • edward
    最后这张图很赞👍

    编辑回复: 谢谢夸奖,希望最后你也可以绘制出自己的知识地图

    2023-08-22归属地:湖南
  • 码小呆
    jvm 对于计算机来说,只能算是一个中间件工具,用于把字节码翻译成计算机能识别的机器码而已!

    编辑回复: 是的,它的本质就是工具,不过如何用好这个工具可是有大学问哦~欢迎交流!

    2023-08-21归属地:广东
  • Calvin
    给大佬点赞666,期待半桶水的自己学习这个课程后能查漏补缺底层知识更精进一些,PS:JVM 虚拟机类比真实的计算机之前我怎么没想到呢?😂 另外我看思考题有提到Thread线程,而 JDK 21 下个月就要 GA 了,到时“虚拟线程”(协程)就正式可用了,不知道利用其结构化编程能力能否实现优化它的目的? 以及大佬会否考虑在后面的章节中添加相关的知识点或者加餐介绍一下这个新特性呢?

    作者回复: 没问题,想了解什么,都可以群里提出来,希望能让你有真正的收获

    2023-08-21归属地:广东
  • 轻风悠扬
    flag应该用volatile来修饰以确保对其他线程可见。

    作者回复: 没问题的,但是volatile的本质是什么,他是如何做到的,volatile和raft协议有什么关系,其实也是可以去思考一下的

    2023-08-21归属地:澳大利亚
  • 老衲
    public class Demo { private AtomicInteger a = new AtomicInteger(0); private volatile boolean flag = false; public void writer() { a = new AtomicInteger(1); flag = true; } public void reader() { if (flag) { int i = a.get() * a.get(); System.out.println(i); } } public static void main(String[] args) throws InterruptedException { final Demo example = new Demo(); Thread thread1 = new Thread(example::writer); Thread thread2 = new Thread(example::reader); thread1.start(); thread2.start(); thread1.join(); thread2.join(); } }
    2023-08-21归属地:广东
    1
    1
收起评论
显示
设置
留言
13
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部