原 架构师视角:对JVM架构进行解析

标签: 架构师 视角 jvm | 发表时间:2018-04-18 21:44 | 作者:
出处:http://www.iteye.com

每一个Java 开发人员都知道字节码由JRE (Java运行时环境)执行。但许多人不知道JRE是Java虚拟机(JVM)的实现, 它负责分析字节码、解析并执行代码。作为一个开发人员了解JVM架构是非常重要的,因为它使我们能更高效的编写代码。在这篇文章中我们将更深入了解Java中的JVM架构以及JVM的各个组件。

JVM是什么?

虚拟机 是物理机器的一个软件实现。Java运行在VM上,实现WORA (一处编写,处处运行)。 编译器将Java文件编译成Java .class 文件,然后这个.class文件被输入到JVM中进行类文件的加载和执行。下面是一个JVM的架构图。

JVM是如何工作的呢?

正如上面的架构图所示,JVM被分为三个主要的子系统:

  1. 类加载器子系统

  2. 运行时数据区

  3. 执行引擎

1. 类加载器子系统

Java的动态类加载功能是由类加载器子系统处理。当它在运行时(不是编译时)首次引用一个类时,它加载、链接并初始化该类文件。

1.1 加载

类由此组件加载。启动类加载器 (Boot Strap class Loader)、扩展类加载器(Extension class Loader)和应用程序类加载器(Application class Loader) 这三种类加载器帮助完成类的加载。

  1. 启动类加载器 – 负责从启动类路径中加载类,无非就是rt.jar。这个加载器会被赋予最高优先级。

  2. 扩展类加载器 – 负责加载ext 目录(jre\lib)内的类.

  3. 应用程序类加载器 – 负责加载应用程序级别类路径,涉及到路径的环境变量等etc.

上述的类加载器会遵循委托层次算法(Delegation Hierarchy Algorithm)加载类文件。

1.2 链接

  1. 校验 – 字节码校验器会校验生成的字节码是否正确,如果校验失败,我们会得到校验错误。

  2. 准备 – 分配内存并初始化默认值给所有的静态变量。

  3. 解析 – 所有符号内存引用被方法区(Method Area)的原始引用所替代。

1.3 初始化

这是类加载的最后阶段,这里所有的静态变量会被赋初始值, 并且静态块将被执行。

2. 运行时数据区(Runtime Data Area)

运行时数据区域被划分为5个主要组件:

  1. 方法区(Method Area) – 所有类级别数据将被存储在这里,包括静态变量。每个JVM只有一个方法区,它是一个共享的资源。

  2. 堆区(Heap Area) – 所有的对象和它们相应的实例变量以及数组将被存储在这里。每个JVM同样只有一个堆区。由于方法区和堆区的内存由多个线程共享,所以存储的数据不是线程安全的。

  3. 栈区(Stack Area) – 对每个线程会单独创建一个运行时栈。对每个函数呼叫会在栈内存生成一个栈帧(Stack Frame)。所有的局部变量将在栈内存中创建。栈区是线程安全的,因为它不是一个共享资源。栈帧被分为三个子实体:

    1.局部变量数组 – 包含多少个与方法相关的局部变量并且相应的值将被存储在这里。

    2.操作数栈 – 如果需要执行任何中间操作,操作数栈作为运行时工作区去执行指令。

    3.帧数据 – 方法的所有符号都保存在这里。在任意异常的情况下,catch块的信息将会被保存在帧数据里面。

    4.PC寄存器 – 每个线程都有一个单独的PC寄存器来保存当前执行指令的地址,一旦该指令被执行,pc寄存器会被更新至下条指令的地址。

    5. 本地方法栈 – 本地方法栈保存本地方法信息。对每一个线程,将创建一个单独的本地方法栈。

3. 执行引擎

分配给运行时数据区的字节码将由执行引擎执行。执行引擎读取字节码并逐段执行。

  1. 解释器 – 解释器能快速的解释字节码,但执行却很慢。 解释器的缺点就是,当一个方法被调用多次,每次都需要重新解释。

  2. JIT 编译器 – JIT编译器消除了解释器的缺点。执行引擎利用解释器转换字节码,但如果是重复的代码则使用JIT编译器将全部字节码编译成本机代码。本机代码将直接用于重复的方法调用,这提高了系统的性能。

1.中间代码生成器 – 生成中间代码

2.代码优化器 – 负责优化上面生成的中间代码

3.目标代码生成器 – 负责生成机器代码或本机代码

4.探测器(Profiler) – 一个特殊的组件,负责寻找被多次调用的方法。

3.垃圾回收器: 收集并删除未引用的对象。可以通过调用"System.gc()"来触发垃圾回收,但并不保证会确实进行垃圾回收。JVM的垃圾回收只收集哪些由new关键字创建的对象。所以,如果不是用new创建的对象,你可以使用finalize函数来执行清理。

如何才能成为一个公司的顶梁柱般架构师呢?

基本知识

1.学会分析源码

程序员每天都和代码打交道。经过数年的基础教育和职业培训,大部分程序员都会「写」代码,或者至少会抄代码和改代码。但是,会读代码的并不在多数,会读代码又真正读懂一些大项目的源码的,少之又少。这种怪状,真要追究起来,怪不得程序员这个群体本身 —— 它是两个原因造成的:

  • 我们所有的教育和培训都在强调怎么写代码,并没有教大家如何读代码

  • 大多数工作场景都是一个萝卜一个坑,我们只需要了解一个系统的局部便能开展工作,读不相干的代码,似乎没用

读源码三问:“为什么要有这样的架构”,“他是什么样子的”,“他是怎么工作的”。

那么阿里程序员是如何去读代码的呢?

2.分布式架构特点及设计理念

首先需要说明的是,分布式系统是一个复杂且宽泛的研究领域,学习一两门在线课程,看一两本书可能都是不能完全覆盖其所有内容的。介于这篇文章是引导初学者入门,所以我个人觉得为初学者介绍一下当前分布式系统领域的全貌,也许比直接推荐论文和课程更有帮助。当初学者对这个领域建立起一个大的 Picture 之后,可以根据自己的兴趣,有选择性的深入不同领域进行进一步的学习。

3.为什么微服务会这么火?

要学习微服务,首先,我们要了解为什么使用微服务。

  • 代码难以理解?

  • 构建和部署耗时长,难以定位问题,开发效率低?

  • 单体只能按整体横向扩展,无法分模块垂直扩展?

  • 一个bug有可能引起整个应用的崩溃?

  • 受技术栈限制,团队成员使用同一框架和语言?

那么如何解决单体的不足呢,通过迁移到微服务架构来解决,我们看一下什么是微服务。

微服务架构:将单体应用拆分为多个高内聚低耦合的小型服务,每个小服务运行在独立进程,由不同的团队开发和维护,服务间采用轻量级通信机制,独立自动部署,可以采用不同的语言及存储。

单体架构整个团队维护开发一个大工程及一个单库,到了微服务架构,用户请求经过API Gateway被路由到下游服务,服务之间以轻量级通信协议进行通信,服务通过注册中心发现彼此,每个服务都有专门的开发维护团队,每个服务对应独立的数据库,服务独立开发,独立部署和上线。

接下来我们总结下微服务的优点。

  • 易于开发与维护

  • 微服务相对小,易于理解

  • 启动时间短,开发效率高

  • 独立部署

  • 一个微服务的修改不需要协调其它服务

  • 伸缩性强

  • 每个服务都可以在横向和纵向上扩展

  • 每个服务都可按硬件资源的需求进行独立扩容

  • 与组织结构相匹配

  • 微服务架构可以更好将架构和组织相匹配

  • 每个团队独立负责某些服务,获得更高的生产力

  • 技术异构性

  • 使用最适合该服务的技术

  • 降低尝试新技术的成本

下面就送上学习架构图吧

如果你觉得想提升下自己,学习文章中的知识,在此推荐一个免费公开课的地方,可以加群:433540541,找群主获取上课资格,这是免费的课程,找群主要的时候可以客气一点。

4.程序员到底要不要学习JVM

总有人问这个东西好像用不上,于是要不要学这样的问题。

然后又总有人担心一直搬砖成天做些重复没提升的东西。

如果你这辈子只甘心做一个平庸的Java码农,那么你完全没有必要去学习JVM相关的知识,学习JVM对于一个Java程序员的好处大概可以概括为下几点:

  • 1.你能够明白为什么Java最早期被称为解释型语言,而后来为什么又被大家叫做解释与编译并存的语言(了解JVM中解释器以及即时编译器就可以回答这个问题);

  • 2.你能够理解动态编译与静态编译的区别,以及动态编译相对于静态编译到底有什么好处(JVM JIT);

  • 3.你能够利用一些工具,jmap, jvisualvm, jstat, jconsole等工具可以辅助你观察Java应用在运行时堆的布局情况,由此你可以通过调整JVM相关参数提高Java应用的性能;

  • 4.可以清楚知道Java程序是如何执行的;

  • 5.可以明白为什么Java等高级语言具有可移植性强的特性。

其实这个问题相当于“为什么C/C++程序员需要学体系结构与编译原理?”

话不多说,附上学习体系图

5.被我们忽略掉的工程化专题

IT产业行业细分化已经不是一天两天的事了。集成技术这件事并不可耻可笑,反而是另一种可贵的能力。并不是像一些人形容的那样,好像批发几个CPU,拿到华强北就能把自己的电脑改装成超级计算机了。

那么,为什么我们常常会忽略掉工程化这件事的价值呢?主要的原因,或许是因为工程化这件事本身就离我们太远。一个产业工程化的普遍性越高,说明这个产业发展的越成熟:产业链细分、分工细化、全球化的研发和生产这些高效的工作方式开始出现。而产业成熟也往往代表着寡头化情况显著。

在IT产业中,寡头化出现代表着创业公司减少——没人再去用声势浩大的发布会讲故事、没人再去宣传自己拿了多少融资。

这一代中国人自小的教育不比欧美的STEAM,而是重学术、轻手艺。我们往往会为工科和产能过剩画上等号。强大的资本和技术门槛为这些产业蒙上了一层神秘的面纱,让普通人很难真正了解到其中技术和工艺的复杂程度,也就更难明白其中的价值。可正是因为中国的工程化能力,才让我们有机会走到AI时代的第一梯队,而不仅仅是靠学术研究能力。

另外一个原因,或许在于我们天生“叛逆心”。超级计算机、手机芯片等等技术门槛较高的产业,其背后往往是大企业和国资科研机构。当评判的对象是他们时,我们似乎更愿意相信狗血的商业故事和阴谋论:比如科研经费都被教授们吃吃喝喝啦;搞超级计算机就是放卫星其实美日根本不care啦;XX企业的技术都是从创业公司买来的除了会赚用户的钱啥技术都没有……

产生这种“叛逆心”的原因太深刻,我们能做到的,只有在这种“惯性思维”出现时先按住自己奔向键盘的手,转表达欲为好奇心,完成自己了解的义务,再去行使自己批判的权利。

附上思维脑图

6.没有高并发经验,想进大公司该怎么办?

假如没有靠谱的公司,接触不到高并发的业务场景怎么办?你永远解决的是小问题,工作10年技术也未必提升多少。

很多程序员也经常找我说,没有经验就没有靠谱的公司收,没有靠谱的公司也就没有经验,我看了无数的书,自己做了无数的实验拼命想找个靠谱公司去深入,但是感觉好难,简直是个死循环

读者群的朋友大家都比较关注高并发,原因很简单,想去BAT这样的大公司,你必须要有高并发的经验。今天普及下高并发的知识,希望大家对高并发有一个正确的认识。

7.学习千遍,不如项目实战成功一次

我们在学习过程中最容易犯的一个错误就是:看的多,动手的少。特别是对一些项目的整体开发,我们接触的机会就更少了。

一次完整的开发,是最好的学习。它能让你对整个开发流程有完整的认识,对知识也会有极大的巩固。更重要的是,你将学会将理论知识用到实际开发中的方法。

所以无论项目大小,一定要动手去进行开发学习。

项目实战相信很多程序员都多少会有的,可是我们这个还要学习什么呢?

那就要看你想不想成为一个架构师了,为什么98%的程序员工作10年,一辈子还只是一个开发者。程序员们都要想一想这个问题,我是不是需要提升了。

我认为,学习项目实战最重要的还是学习项目管理,作为程序员,都应该学点项目管理。

  1. 凡事皆为“项目”

  2. 项目的两类属性(复杂的逻辑,庞大的信息量)

  3. 人脑擅长的是思考,而不是记忆

  4. 成为一个“独当一面”的人

独当一面是一个很性感的词。是否拥有它,对应的职场价值,有着天壤之别的。

所有老板都喜欢“独当一面”的员工,因为这是最省心力、最好算账的模式:给你一块资源,给你一个 title,给你一个目标,然后你给我打出一片天地来。

当你能独立对一摊子事情负责,并把它们一一搞定,你会拥有大幅度的职场溢价——相应的,其收入回报,也远非“技术螺丝”可比了。

如果你很进取,你会逐渐地:主导一个小组,一个部门,一个家庭,甚至还是城市……而这所有的一切起点,正是独立完整地做好一个项目:你没有谁可以依靠,你要对其中大大小小的事务负责,你要对最后的结果。

换句话说,“项目管理”是“独当一面”的元能力。在这个过程中,你的意识越发清晰,你的方法论越发成熟,你的信心更加沛,项目越做越大。直到某天,你真的有了掌控一方的封疆大吏。

这就是我们学习“项目实战”的终极意义。

或许作为程序员的你想提升自己,却找不到突破口,公司没人带。又或许你已经工作6年了,却还是很迷茫,很多知识都还是不懂,也没有达到自己期望的一个职位,薪资。在此推荐一个免费公开课的地方,上面所提到的架构师基本知识点都有资料,可以加群:433540541,找群主获取上课资格,这是免费的课程,找群主要的时候可以客气一点。

到这里,你可能认为文章已经完了,学完这些就可以去BAT大公司做一个架构师,年薪50W+吗?

不,你错了,这些都知识最基本的知识,想要成为一个架构师必须是一个累积的过程,也是这么多程序员终其一生也只是一个开发,到年龄就会被公司辞退。

 


已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [架构师 视角 jvm] 推荐:

原 架构师视角:对JVM架构进行解析

- - ITeye博客
每一个Java 开发人员都知道字节码由JRE (Java运行时环境)执行. 但许多人不知道JRE是Java虚拟机(JVM)的实现, 它负责分析字节码、解析并执行代码. 作为一个开发人员了解JVM架构是非常重要的,因为它使我们能更高效的编写代码. 在这篇文章中我们将更深入了解Java中的JVM架构以及JVM的各个组件.

JVM研究

- - 开源软件 - ITeye博客
每天接客户的电话都是战战兢兢的,生怕再出什么幺蛾子了. 我想Java做的久一点的都有这样的经历,那这些问题的最终根结是在哪呢. JVM全称是Java Virtual Machine,Java虚拟机,也就是在计算机上再虚拟一个计算机,这和我们使用 VMWare不一样,那个虚拟的东西你是可以看到的,这个JVM你是看不到的,它存在内存中.

jvm调优

- - 互联网 - ITeye博客
printf "%x\n" 21742  找到耗时最长的进程. jstack pid | grep 54ee  定位某个类的方法. jstack 10535|grep -A 10 2a1d (最后十行). jmap 查询pid 内存线程. 附:TOP命令中需要关注的值:. (1)load average:此值反映了任务队列的平均长度;如果此值超过了CPU数量,则表示当前CPU数量不足以处理任务,负载过高.

学习JVM的References

- LightingMan - 淘宝JAVA中间件团队博客
本blog中列举了我学习JVM的references,会不断的更新,为了避免版权问题,就不在blog上提供references的下载了,感兴趣的同学可自行下载或购买,:). |— [ Hotspot GC论文 ]. |— [ 其他JVM GC ]. |— Linux内核源代码情景分析. |— Linux 内核中断内幕.

深入理解JVM

- 小伟 - ITeye论坛最新讨论
1   Java技术与Java虚拟机. 说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成: Java编程语言、Java类文件格式、Java虚拟机和Java应用程序接口(Java API). 图1   Java四个方面的关系. 运行期环境代表着Java平台,开发人员编写Java代码(.java文件),然后将之编译成字节码(.class文件).

jvm垃圾回收

- Cano - 淘宝共享数据平台 tbdata.org
在jvm中堆空间划分为三个代:年轻代(Young Generation)、年老代(Old Generation)和永久代(Permanent Generation). 年轻代和年老代是存储动态产生的对象. 永久带主要是存储的是java的类信息,包括解析得到的方法、属性、字段等等. 我们这里讨论的垃圾回收主要是针对年轻代和年老代.

JVM内存分配

- - 移动开发 - ITeye博客
计算机内存,它算是CPU与计算机打交道最频繁的区域,所有数据都是先经过硬盘至内存,然后由CPU再从内存中获取数据进行处理,又将数据保存到内存,通过分页或分片技术将内存中的数据再flush至硬盘. 那JVM的内存结构到底是如何呢. JVM做为一个运行在操作系统上,但又独立于os运行的平台,它的内存至少应该包括象寄存器、堆栈等区域.

Azul开源Zing Jvm

- - InfoQ cn
4月末,继Zing 5.2 之后,. Azul Systems宣布他们将无停顿(pauseless )的 Zing JVM提供给开源软件开发者和项目,以供开发和测试. Azul Systems 工程部副总裁和合作创始人Shyam Pillalamarri向InfoQ说明道:. 我们的部署很大一部分基于开源组件,所以我们认为:“假设我们不能将一些有价值的东西免费提供给开源项目贡献者,他们将一直受限于从Java虚拟机(JVM)视角所看到的内容”,他们将不会考虑额外的用例,或者选择其他能解决了所有内存或扩展性问题、类似Zing的系统.

JVM参数设置

- - 企业架构 - ITeye博客
-Xms768m -Xmx1280m  jvm堆的最小值和最大值设置,一般设成相同值,避免频繁分配堆空间. -XX:NewSize=128m -XX:MaxNewSize=128m  年轻代最小值和最大值设置(年轻代设定了,年老代也就定了),也可以用参数-XX:NewRatio=4,年老代和年轻代的大小比,这里128m有点小了,官方建议的是heap的3/8,差不多280m.

JVM的DirectMemory设置

- - 编程语言 - ITeye博客
原文: http://dongliu.net/post/504141. 几台服务器的JVM占用内存总是持续增长,大大超过-Xmx设定的值,服务器物理内存几乎被耗尽. 使用jmap查看JVM的内存使用,发现jvm的堆大小完全在-Xmx参数设定的范围之内,那问题只能处在别的地方了. JVM除了堆内存之外,就只有栈内存和DirectMemory了.