Learn && Live
虚度年华浮萍于世,勤学善思至死不渝
本文主要参考了周志明老师所著《深入理解Java虚拟机》,如有纰漏偏差,欢迎各位大佬指正!原创不易,转载请注明出处:http://t.csdn.cn/UORhr
相信在简历中赫然列出“熟悉Java编程语言”的你对下面这幅图一定不会感到陌生吧,JVM体系结构作为各大面经文章的常客,即将带领我们进入深入理解JVM的崭新世界。
由上图可见,JVM的体系结构包含以下五大部分:
类加载器子系统(Class Loader SubSystem)
运行时数据区(Runtime Data Area)
执行引擎(Execution Engine)
本地库接口(Java Native Interface)
本地方法库(Native Method Libraries)
那么上述这五大部分各自发挥着怎样的作用呢?我们平时写出的代码又是怎么跑起来的呢?
五大部分各自的作用会在后续的学习中逐步细化,这里只给出简述。
我们平时写代码得到的java文件,经过编译器编译生成字节码文件
通过类加载器(Class Loader)加载到JVM中
由运行时数据区(Runtime Data Area)将字节码加载到内存中
字节码文件只是针对JVM的一套指令集规范,并不能直接交给底层操作系统去执行,需要将字节码文件经执行引擎(Execute Engine,实际是执行引擎中的即时编译器)编译成具体的机器码
根据生成的机器码找到对应的本地接口,调用操作系统的本地方法库完成具体的指令操作
如此这般,我们的代码历经五道关卡,就可以顺利地跑起来了。
在多核操作系统上,JVM允许在一个进程内并发执行多个线程。
JVM中的线程与底层操作系统中的线程是相互对应的,在JVM线程的本地存储、缓冲区分配、同步对象、栈、程序计数器等准备工作完成后,JVM会调用操作系统的接口创建一个与之对应的操作系统原生线程;在JVM线程运行结束时,原生线程也会被回收
JVM后台运行的线程主要有:虚拟机线程、周期性任务线程、GC线程、编译器线程、信号分发线程。
首先明确下面几个JVM线程的相关概念,方便我们之后对各个区域的展开学习:
明确了JVM线程的相关概念后,我们就可以继续深入运行时数据区的各个子区域了
有一定计算机基础的小伙伴对这个名字一定不会陌生,事实上它的作用也是与操作系统中的类似。
相信之前在学习Java的基础内容是你一定了解过这样一个概念:在Java代码中定义的局部变量(方法内定义的变量)被存储到JVM中的栈中,按照栈后进先出(FILO)的方式进行维护。但你同时可能也会有这样一个疑问:既然局部变量是定义在方法内的,那如果我们不对这些变量做一定的区分,一股脑地塞到栈中,那么在被所在的方法调用时会是怎样“壮观”的景象呢?相信下面的解释会让你豁然开朗。
JVM栈的特点概念:
又名本地方法栈(Native Method Stack)。
线程共享
存放已被JVM加载的类信息、final常量、static静态变量、即时编译器编译后的代码等数据
不需要连续的内存空间,可选择固定大小或可扩展,可以选择不实现垃圾回收
方法区的垃圾回收主要涉及:(这里会在之后垃圾回收算法部分详细介绍)
异常情况:方法区不足以分配新的内存空间,抛出OutOfMemoryError
说到GC机制和经典分代的设计方法,你一定听到过**“永久代”**这一概念,甚至会在很多前辈的文章中看到将方法区等同于永久代,而事实真的如此吗?事实上两者是不等价的,下面以JDK版本作为时间轴解释
运行时常量池
方法区的一部分
存放常量池表(Constant Pool Table),包含编译期生成的各种字面量、符号引用及符号引用翻译得到的直接引用
字面量:int a = 1;中的1,String = “abc”;中的“abc”
符号引用:一组由任意形式的字面量组成的符号,唯一标记一个不清楚所引用目标实际地址的类,如在A类中引用的B类,与JVM内存布局无关,所引用的类不一定加载到内存中
直接引用:与符号引用相对应,与JVM布局相关,所引用的目标会加载到内存中,不同的JVM翻译所得结果不同。实现方式包括指针/地址、相对偏移量(下标)、间接定位句柄(这里先mark一下,需要后续了解学习)
**动态性。**常量不一定只有编译期才能产生,运行期间也可以加入新的常量(intern()方法)
异常情况:方法区内存OutOfMemoryError
不是运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域
NIO可以使用Native函数库直接分配堆外内存,然后通过堆中的DirectByteBuffer对象作为这块内存的引用进行操作,可以显著提高执行效率(有cache那味了哈)
直接内存的分配不会受到Java堆大小的限制,但总会受到本机内存空间的限制,因此超出内存限制时也会抛出OOMError
种一棵树最好的时间是十年前,其次是现在
首先真的十分感谢你能够看到这里,感谢每一位来到这里的朋友对我的支持
这篇文章是作为科班出身的我,在大学三年的时光中发出的第一篇博客,也是我人生中创作的第一篇博客
回顾三年编程路上的寻觅与探索,从一字一句的纸质笔记,到利用md、pad完成的一篇篇电子笔记,算起来也留下了不少我在这三年“活过”的痕迹,但总觉得缺了点什么,总觉得和一起同行的朋友们差了些什么
直至最近看到很多朋友的博客、看到很多大佬用心创作的文章,我恍然大悟,找到了自己找寻了三年也没有找到的东西:分享,过去的三年中我大多处于闭门造车的状态,做笔记也只是将基础知识加上一点自己的看法、总结记录下来,对或错又有谁清楚?
但博客截然不同,在这里哪怕只是作为一种记录、一种分享,我也能感到以一种无形的责任与使命,驱动着自己向更深更广挖掘,尽可能全面、准确的表现出来,而这样深入探索的过程,让我感到前所未有的满足与快乐
“混了三年才写了一篇博客”,是的,但请在其中加个“第”字,种一棵树最好的时间是三年前,其次是现在,正如我的人生信条:勤学善思至死不渝,不要在乎起点在哪,而更要关注追逐的过程和冲向终点的喜悦……
那就让我们从现在出发吧。一起加油,努力记录自己每一次学习的过程!
,而这样深入探索的过程,让我感到前所未有的满足与快乐
“混了三年才写了一篇博客”,是的,但请在其中加个“第”字,种一棵树最好的时间是三年前,其次是现在,正如我的人生信条:勤学善思至死不渝,不要在乎起点在哪,而更要关注追逐的过程和冲向终点的喜悦……
那就让我们从现在出发吧。一起加油,努力记录自己每一次学习的过程!
十分欢迎各位大佬前辈针对内容和创作提出宝贵的意见,感谢阅读!