大数据面试(一)之JVM
大数据面试(一)之JVM
1、JVM的基本概念
JVM是用于运行Java字节码的虚拟机,包括一套字节码指令集,一组程序寄存器,一个虚拟机栈,一个虚拟机堆,一个方法区及一个垃圾回收器。JVM运行在操作系统之上,不与硬件设备直接交互。
Java程序的具体运行过程:
①Java源文件被编译器编译成字节码文件。
②JVM将字节码文件编译成相应操作系统的机器码(Java能够跨平台的原因)
③机器码调用相应操作系统的本地方法库执行相应的方法
2、JVM构成
● 类加载器子系统用来将编译好的.Class文件加载到JVM中;
● 运行时数据区用于存储在JVM运行过程中产生的数据,包括程序计数器、方法区、本地方法区、虚拟机栈及虚拟机堆;
● 执行引擎包括即时编译器和垃圾回收器,即时编译器用于将java字节码编译成具体的机器码,垃圾回收器用于回收运行时不再使用的对象。
● 本地接口库用于调用操作系统的本地方法库完成具体的指令操作。
3、多线程
在多核操作系统上,JVM允许在一个进程内同时并发执行多个线程。JVM中的线程与操作系统中的线程是相互对应的, 在JVM线程的本地存储、缓冲区分配、同步对象、栈、程序计数器等准备工作都完成时,JVM会调用操作系统的接口创建一个与之对应的原生线程;在JVM线程运行结束时,原生线程随之被回收。操作系统负责调度所有线程,并为其分配CPU时间片,在原生线程初始化完毕时,就会调用Java线程的run()执行该线程;在线程结束时,会释放原生线程和Java线程所对应的资源。
4、JVM的内存区域
JVM的内存区域分为线程私有区域(程序计数器,虚拟机栈,本地方法区),线程共享区域(堆,方法区)和直接内存
线程私有区域的生命周期与线程相同,随线程的启动而创建,随线程的结束而销毁。在JVM内部,每个线程都与操作系统的本地线程直接映射,因此线程私有内存区域的存在与否和本地线程的启动和销毁对应。
线程的共享区域随虚拟机的启动而创建,随虚拟机的关闭而销毁。
直接内存也叫堆外内存,它并不是JVM运行时数据区的一部分,但在并发编程中被频繁使用。JDK的NIO模块提供基于Channel与Buffer的I/O操作方式就是基于堆外内存实现的,NIO模块通过调用Native函数库直接在操作系统上分配堆外内存,然后使用DirectByteBuffer对象作为这块内存的引用堆内存进行操作,Java进程可以通过堆外内存技术避免在Java堆和Native堆中来回复制数据带来的资源浪费和性能消耗,因此堆外内存在高并发应用场景下被广泛应用(Netty,Flink,HBase,Hadoop都有用到堆外内存)
4.1、程序计数器:线程私有,无内存溢出问题
程序计数器是一块很小的内存空间,用于存储当前运行的线程所执行的字节码的行号指示器。每个运行中的线程都有一个独立的程序计数器,在方法正在执行时,该方法的程序计数器记录的是实时虚拟机字节码指令地址;如果该方法执行的是Native方法,则程序计数器的值为空
程序计数器属于线程私有的内存区域,它是唯一没有内存溢出的区域。
4.2、虚拟机栈:线程私有,描述Java方法的执行过程
虚拟机站是描述Java方法的执行过程中的内存模型,它在当前栈帧中存储了局部变量表,操作数栈,动态链接,方法出口等信息。同时,栈帧用来存储部分,运行时数据及其数据结构,处理动态链接方法的返回值和异常分派。
4.2、本地方法区:线程私有
本地方法区和虚拟机栈作用类似,区别是虚拟机栈为执行Java方法服务,本地方法栈为Native方法服务
4.4、堆:也叫做运行时数据区,线程共享
在JVM运行的过程中创建的对象和产生的数据都被存储在堆中,堆是被线程共享的内存区域,也是垃圾收集器进行垃圾回收的最主要的内存区域。由于现代JVM采用分代收集算法,因此Java堆从GC的角度还可以细分为:新生代,老年代和永久代
4.5、方法区:线程共享
方法区也被称为永久代,用于存储常量,静态变量,类信息,即时编译器编译后的机器码,运行时常量池等数据