撸完这篇JVM知识点,面试字节跳动被当场拟录取,我飘了

跟许多人一样,我一开始接触 Java 虚拟机只是因为面试需要用到,所以硬着头皮看看。所以很多人对于为什么要学虚拟机这个问题,他们的答案都是:因为面试。但我经过了几年的学习和实战,我发现其实学习虚拟机并不仅仅在于面试,而在于更深入地理解 Java 这门语言,以及为未来排查线上问题打下基础。

对于刚刚工作一两年的朋友来说,各个 API 都没用熟,自然不会去深入研究 Java 中的各种细节。但对于工作了三年以后的朋友来说,很多时候你要解决一个问题必须深入到字节码层次去分析,你才能得到准确的结论,而字节码就是虚拟机的一部分。所以学习JVM就不仅仅是为了面试,更是需要在实际工作中使用,能力越大,责任越大。

我是「猿码天地」,一个热爱技术、热爱编程的IT猿。技术是开源的,知识是共享的!  

写作是对自己学习的总结和记录,如果您对Java、分布式、微服务、中间件、Spring Boot、Spring Cloud等技术感兴趣,可以关注我的动态,我们一起学习,一起成长! 

用知识改变命运,让家人过上更好的生活,互联网人一家亲!

微信搜索「猿码天地」,回复「电子书」白嫖1000本Java开发精华电子书,回复「BAT面试」获取最新国内一线大厂Java面试题!

我的微信:zhangbowen125 有任何问题欢迎私聊咨询!

先来一波福利

猿码天地-Java知识学堂脑图 (文件密码:请关注公众号【猿码天地】,回复关键字‘活到老学到老’获取)

猿码天地-Java超神之路脑图 (文件密码:请关注公众号【猿码天地】,回复关键字‘活到老学到老’获取)

文章结尾还有月薪3万Java优秀简历模板、全网最全一线大厂Java笔试面试题、1000+本Java开发精华电子书送给大家,希望大家认真学习哦!

猿人花了一个星期的时间,为大家整理了JVM核心知识点。包括5个部分:JVM基本概念及内存区域、JVM 运行时内存结构(Run-Time Data Areas)、JVM类加载机制、垃圾回收与算法、GC垃圾收集器,通过这5个部分的学习,完全可以掌握JVM核心知识点,面试一线大厂完全没问题。

JVM基本概念及内存区域

1、基本概念

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

2、运行过程

我们都知道 Java 源文件,通过编译器,能够生产相应的.Class 文件,也就是字节码文件, 而字节码文件又通过 Java 虚拟机中的解释器,编译成特定机器上的机器码 。

也就是如下:

  • Java 源文件—》编译器—》字节码文件
  • 字节码文件—》JVM—》机器码

每一种平台的解释器是不同的,但是实现的虚拟机是相同的,这也就是 Java 为什么能够跨平台的原因了 ,当一个程序从开始运行,这时虚拟机就开始实例化了,多个程序启动就会存在多个虚拟机实例。程序退出或者关闭,则虚拟机实例消亡,多个虚拟机实例之间数据不 能共享。

先来看看JVM有哪些区域

第一,JVM分为五个区域:虚拟机栈、本地方法栈、程序计数器、方法区、堆。PS:大家不要排斥英语,此处用英文记忆反而更容易理解。

第二,JVM五个区中虚拟机栈、本地方法栈、程序计数器为线程私有,方法区和堆为线程共享区。下图中已经用颜色区分,绿色表示“通行”,橘黄色表示停一停(需等待)。

第三,JVM不同区域的占用内存大小不同,一般情况下堆最大,程序计数器较小。那么最大的区域会放什么?当然就是Java中最多的“对象”了。

3、内存区域

JVM 内存区域主要分为虚拟机栈、本地方法栈、程序计数器、方法区、堆,其中程序计数器、虚拟机栈和本地方法栈为线程私有,堆和方法区为线程共有。

线程私有数据区域生命周期与线程相同, 依赖用户线程的启动/结束 而 创建/销毁(在 Hotspot VM 内, 每个线程都与操作系统的本地线程直接映射, 因此这部分内存区域的存/否跟随本地线程的生/死对应)。

线程共享区域随虚拟机的启动/关闭而创建/销毁。

好,接下来我们就对虚拟机栈、本地方法栈、程序计数器、方法区、堆进行详细讲解。

来来来,接下来,看一看pdf截图,都是猿人整理的哦,熬夜伤不起啊!

JVM核心知识点pdf文档获取方式:百度网盘,提取码:tzp5

JVM 运行时内存结构(Run-Time Data Areas)

Java 虚拟机定义了在程序执行期间使用的各种运行时数据区域。其中一些数据区域所有线程共享,在 Java 虚拟机(JVM)启动时创建,仅在 Java 虚拟机退出时销毁。还有一些数据区域是每个线程的。线程数据区域是在线程启动时创建,线程结束时销毁。

JVM在程序运行过程当中,会创建大量的对象,这些对象,大部分是短周期的对象,小部分是长周期的对象,对于短周期的对象,需要频繁地进行垃圾回收以保证无用对象尽早被释放掉,对于长周期对象,则不需要频率垃圾回收以确保无谓地垃圾扫描检测。为解决这种矛盾,Sun JVM的内存管理采用分代的策略。

1、运行时数据区划分
  • The pc Register(PC 寄存器、程序计数器)
  • Java Virtual Machine Stacks(Java 虚拟机栈、Java 栈)
  • Native Method Stacks(本地方法栈,C栈)
  • Heap(堆)
  • Method Area(方法区,JDK8 中的实现叫元数据区(本地内存中),JDK7 中的实现叫永久代(JVM中))
  • Run-Time Constant Pool(运行时常量池,方法区的一部分)
2、Heap(堆)详解

在JVM基本概念及内存区域文章中,猿人已经为大家介绍了运行时数据区各个模块的功能。主要包括虚拟机栈、本地方法栈、程序计数器、方法区、堆等信息。

堆主要用于存放各种类的实例对象和数组。在java中被分为两个区域:年轻代和老年代。在java中还有一个永久代的意思,这里最后会单独说明。

作为运行时数据区非常重要的一块内存,Heap(堆), 堆是被线程共享的一块内存区域,创建的对象和数组都保存在 Java 堆内存中,也是垃圾收集器进行垃圾收集的最重要的内存区域。

由于现代 VM 采用分代收集算法, 因此堆从 GC 的角度还可以 细分为: 新生代(Eden 区、From Survivor 区和 To Survivor 区)和老年代。

  • 第一,堆的GC操作采用分代收集算法。
  • 第二,堆区分了新生代和老年代。
  • 第三,新生代又分为:Eden空间、From Survivor(S0)空间、To Survivor(S1)空间。

Java虚拟机规范规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。也就是说堆的内存是一块块拼凑起来的。要增加堆空间时,往上“拼凑”(可扩展性)即可,但当堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

对于新生代和老年代,如何划分,对象在堆中的生命周期,以及面试官:为什么新生代内存需要有两个Survivor区 S0、S1?都是需要我们去思考的。由于篇幅有限,直接把pdf文档贡献给大家!
JVM核心知识点pdf文档获取方式:百度网盘,提取码:tzp5

JVM类加载机制

JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程。

1、JVM类加载机制

加载

在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main()方法,new对象等等,在加载阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

验证

校验字节码文件的正确性,这一阶段的主要目的是为了确保 Class 文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

准备

给类的静态变量分配内存,并赋予默认值。

解析

解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程。符号引用就是 class 文件中 的:

  1. CONSTANT_Class_info
  2. CONSTANT_Field_info
  3. CONSTANT_Method_info

初始化

对类的静态变量初始化为指定的值,执行静态代码块。初始化阶段是类加载最后一个阶段,前面的类加载阶段之后,除了在加载阶段可以自定义类加载 器以外,其它操作都由 JVM 主导。到了初始阶段,才开始真正执行类中定义的 Java 程序代码。

2、类加载器

虚拟机设计团队把加载动作放到 JVM 外部实现,以便让应用程序决定如何获取所需的类,JVM 提供了 3 种类加载器:

ClassLoad:类加载器用来加载 Java 类到 Java 虚拟机中。

Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)

类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。

jdk中提供了三种类加载器:

  • 引导类加载器BootStrap ClassLoader
  • 扩展类加载器Extension ClassLoader
  • 应用类加载器Application ClassLoader

Extension ClassLoader和Application ClassLoader被定义在Launcher类中,BootStrap ClassLoader则是使用c++实现的,在jdk中无法直接找到。

引导类加载器BootStrap ClassLoader:负责加载支撑JVM运行的位于JRE的lib目录下核心类库,比如rt.jar、charsets.jar等
扩展类加载器Extension ClassLoader:负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包
应用类加载器Application ClassLoader:负责加载ClassPath路径下的类包,主要就是加载你自己写的那些类
3、双亲委派

当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到引导类加载其中, 只有当父类加载器反馈自己无法完成这个请求的时候 (在它的加载路径下没有找到所需加载的 Class),子类加载器才会尝试自己去加载。

采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的引导类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个 Object 对象。

为什么要使用双亲委派机制?
  • 沙箱安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心API库被随意篡改
  • 避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次,保证被加载类的唯一性
JVM核心知识点pdf文档获取方式:百度网盘,提取码:tzp5

粉丝福利

猿码天地-Java知识学堂脑图 (文件密码:请关注公众号【猿码天地】,回复关键字‘活到老学到老’获取)
猿码天地-Java超神之路脑图 (文件密码:请关注公众号【猿码天地】,回复关键字‘活到老学到老’获取)

福利一:月薪3万Java优秀简历模板

简历是对你过往学习和工作的一个总结,一份好的简历容易给人留下深刻印象,更容易被企业发现,创造更多的就业机会。优秀的简历可以把你推销给优秀的企业,看看别人的优秀简历范文,让自己的简历更加优秀吧。

可以在微信搜索「猿码天地」,关注后回复关键字「简历」即可获取!

福利二:全网最全一线大厂Java笔试面试题

面试题涵盖了Spring核心知识、SpringMVC、SpirngBoot、SpringCloud、JVM、数据库、常用消息组件Kafka、RabbitMQ、分布式、微服务组件Eureka、Ribbon、Config、Feign、Nacos、Zookeeper等、SQL优化、常用服务器Tomcat、Nginx、多线程、高并发等等。

可以在微信搜索「猿码天地」,关注后回复关键字「BAT面试」即可获取!

福利三:1000+本Java开发精华电子书

猿人从事Java开发多年,从最初的小白,一步步通过自己不断的学习、摸索,终于走上了码农这条没有回头的路。学习是无止境的,有时零零散散的学习资料难以将我们的知识成体系的串联起来。为此,为了让大家在学习Java的道路上成系统的学习,少走弯路,猿人为大家整理了1000+本Java开发精华电子书,毕竟现在电子书也是挺贵的,哈哈,希望能给大家带来帮助。

电子书涵盖:Java入门、并发编程、底层、常用框架、性能优化、设计模式、工具、计算机网络、操作系统、数据库、数据结构与算法、大数据、架构设计、Linux知识、面试、扩展、管理、容器化技术、云计算、微服务、领域设计等方方面面,猿人还会给持续更新。

获取方式

第一种:微信搜索「猿码天地」或者扫描下面的二维码,关注后回复关键字「电子书」即可获取!

第二种:Gitee:https://gitee.com/zhangbw666/java-books

希望程序员朋友能认真学习,根据自身需要获取对应的电子书,学习是永无止境的。

你多学一样本事,就少说一句求人的话,现在的努力,是为了以后的不求别人,实力是最强的底气。记住,活着不是靠泪水博得同情,而是靠汗水赢得掌声。
——《写给程序员朋友》

福利送完了,我们接下来还有两块任务,也是面试和实际工作中必须掌握的,那就是垃圾回收与算法和GC垃圾收集器。来,跟着猿人一起干了它。

垃圾回收与算法

垃圾回收(GC)是JVM的一大杀器,它使程序员可以更高效地专注于程序的开发设计,而不用过多地考虑对象的创建销毁等操作。但是这并不是说程序员不需要了解GC。GC只是Java编程中一项自动化工具,任何一个工具都有它适用的范围,当超出它的范围的时候,可能它将不是那么自动,而是需要人工去了解与适应地适用。

拥有一定工作年限的程序员,在工作期间肯定会经常碰到像内存溢出、内存泄露、高并发的场景。这时候在应对这些问题或场景时,如果对GC不了解,很可能会成为个人的发展瓶颈。

垃圾回收需要完成的三件事:

  • 哪些内存需要回收?—如何确定垃圾?(引用计数法、可达性分析算法)
  • 如何回收?——垃圾回收算法(标记复制(新生代)、标记清除(几乎不用)、标记整理(老年代)、分代收集)
  • 何时回收?

直接给粉丝们上干货,pdf文档拿走,不谢!

JVM核心知识点pdf文档获取方式:百度网盘,提取码:tzp5

GC垃圾收集

在我们的经验之中,大部分的对象在生成之后就会马上变成垃圾,很少有对象能够或很久。这个就是我们将对象分成新生代和老年代的依据。在不同的代采用不同的收集算法,从而提高内存的利用率。

我们的分区一般如下图所示,一个生成空间,两个大小相等的幸存空间,一个老年代空间。而针对它们的回收,我们的叫法也不相同。

新生代GC(minor GC):指发生在新生代的垃圾回收动作,因为Java对象大多都具备朝生夕灭的特点,所以minor GC发生得非常频繁,一般回收速度也比较块。

老年代GC(Major GC/Full GC):指发生在老年代的GC,它的速度会比minor GC慢很多。

Java 堆内存被划分为新生代和年老代两部分,新生代主要使用标记-复制和标记-清除垃圾回收算法; 年老代主要使用标记-整理垃圾回收算法,因此 java 虚拟中针对新生代和年老代分别提供了多种不同的垃圾收集器,JDK Sun HotSpot 虚拟机的垃圾收集器如下:

更多内容,就见文档啦!

JVM核心知识点pdf文档获取方式:百度网盘,提取码:tzp5
面试官:日均百万级订单交易系统如何设置JVM参数?

结论:通过上面这些内容介绍,大家应该对JVM优化有些概念了,就是尽可能让对象都在新生代里分配和回收,尽量别让太多对象频繁进入老年代,避免频繁对老年代进行垃圾回收,同时给系统充足的内存大小,避免新生代频繁的进行垃圾回收。

猿码天地-Java知识学堂脑图 (文件密码:请关注公众号【猿码天地】,回复关键字‘活到老学到老’获取)

猿码天地-Java超神之路脑图 (文件密码:请关注公众号【猿码天地】,回复关键字‘活到老学到老’获取)

你多学一样本事,就少说一句求人的话,现在的努力,是为了以后的不求别人,实力是最强的底气。记住,活着不是靠泪水博得同情,而是靠汗水赢得掌声。
——《写给程序员朋友》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿码天地

相互学习,谢谢您的打赏。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值