简单了解JVM基础知识

JVM原理

- 什么是JVM?

基于栈的体系结构
1)Java Virtual Machine 缩写、是一种基于计算设备的规范,是一台虚拟机,即虚构的计算机。
2)JVM屏蔽了与具体操作系统平台相关的信息Java语言在不同平台运行时不需要重新编译,只需要在该平台上部署JVM就可以了。因而能实现一次编译多处运行。
3)当然,JVM执行字节码时实际上还是要解释成具体操作平台的机器指令的。
4) JVM本质上就是一个程序,当它在命令行上启动的时候,就开始执行保存在某字节码文件中的指令。

- JRE/JDK/JVM是什么关系

1、JRE(JavaRuntimeEnvironment,Java运行环境),也就是Java平台。
所有的Java 程序都要在JRE下才能运行。普通用户只需要运行已开发好的java程序,安装JRE即可。
2、JDK(Java Development Kit)是程序开发者用来编译、调试java程序用的开发工具包。
JDK本体也是Java程序,因此运行依赖于JRE,由于需要保持JDK的独立性与完整性,JDK的安装目录下通常也附有JRE。
目前Oracle提供的Windows下的JDK安装工具会同时安装一个正常的JRE和隶属于JDK目录下的JRE。
3、JVM是JRE的一部分。使用JVM就是为了支持与操作系统无关,实现跨平台。

- JVM结构

JVM主要包括:程序计数器(Program Counter),Java堆(Heap),Java虚拟机栈(Stack),本地方法栈(Native Stack),方法区(Method Area)

1. 程序计数器(Program Counter)

1)是一个寄存器,可以看作是代码行号指令器,类似于实际计算机里的PC,用于指令、跳转下一条需要执行的命令
2)JVM多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的。在一个确定的时刻,一个处理器(或者说多核处理器的一个内核)只会执行一条线程中的命令。
3)因此,为了正常的切换线程,每个线程都会有一个独立的PC,各线程的PC不会互相影响。这个私有的PC所占的这块内存即是线程的“私有内存”。
4)如果线程在执行的是Java方法,那么PC记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的不是Java方法即Native方法,那么PC的值为undefined。
5)PC的内存区域是唯一的没有规定任何OutOfMemoryError的Java虚拟机规范中的区域。

2. Java虚拟机栈(Stack)

1) 同PC一样也是线程私有的,生命周期与线程相同。虚拟机栈描述Java方法执行的内存模型,每个方法被执行时都会创建一个栈帧(Stack Frame)
2) 栈帧会利用 局部变量数组 存储局部变量(Local Variables),操作栈(Operand Stack),方法出口(Return Value),动态连接(Current Class Constant Pool Reference)等信息。
3) 局部变量数组 存储了编译可知的八个基本类型、对象引用、returnAddress类型
4) 在编译期间,局部变量所需的空间就会完成分配,动态运行期间不会改变所需的空间。
5) 操作栈在执行字节码指令时会被用到,这种方式类似于原生的CPU寄存器,大部分JVM把时间花费在操作栈的花费上,操作栈和局部变量数组会频繁的交换数据。
6) 动态连接控制着运行时常量池和栈帧的连接。所有方法和类的引用都会被当作符号的引用存在常量池中。

3. 本地方法栈(Native Stack)

本地方法栈如其名字,和Java Virtual Machine Stack其实极为类似,只是执行的是Native方法,为Native方法服务。
在JVM规范中,没有对它的实现做具体规定。

4. Java堆(Heap)

1) Java堆是被所有线程共享的一块区域,在虚拟机启动时创建。
2) 此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存(随着技术的发展,已不绝对)。
3) Java堆是垃圾收集器管理的主要区域,因而也被称为GC堆。
4) 收集器采用分代回收法,GC堆可以分为新生代(Yong Generation)和老生代(Old Generation)。新生代包括Eden Space和Survivor Space。但无论哪个区域,如何划分,存储的都是Java对象实例,进一步的划分是为了更好的回收内存或快速的分配内存。
5) 根据Java虚拟机规范,堆所在的物理内存区间可以是不连续的,只要逻辑连续就可以。实现时既可以是固定大小,也可以是可扩展的。如果堆无法扩展时,就会抛出OutOfMemoryError。

5. 方法区(Method Area)

1) 方法区和Java堆类似,也属于各线程共享的内存区域。
2) 用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码数据等。
3) 它属于非堆区(Non Heap),和Java堆区分开。
4)对于存在永久代(Permanent)概念的虚拟机(HotSpot)而言,方法区存在于永久代。
5  Java虚拟机规范对方法区的规定很宽松,甚至可以不实现GC。不过并非进入方法区的数据就会永久存在了,这块区域的内存回收主要为常量池的回收和类型的卸载。
6)这个区域的回收处理不善也会导致严重的内存泄漏。
7)当方法区无法满足内存分配需求时也会抛出OutOfMemoryError。

6. 代码缓存(Code Cache)

用于编译和存储那些被 JIT 编译器编译成原生代码的方法。

7. 类信息(Class Data)

类信息存储在方法区,其主要构成为运行时常量池(Run-Time Constant Pool)和方法(Method Code)。‘’

8. 运行时常量池(Run-Time Constant Pool)

1) 运行时常量池是方法区的一部分。
2) Class文件中有类的版本,字段,方法,接口等描述信息和用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
3) Java虚拟机规范对Class的细节有着严苛的要求而对运行时常量池的实现不做要求。一般来说除了翻译的Class,翻译出来的直接引用也会存在运行时常量池中。
4) 运行时常量池具备动态性,即运行时也可将新的常量放入池中。比如String类的intern()方法。
5) 常量池无法申请到足够的内存分配时也会抛出OutOfMemoryError。

9. 直接内存(Direct Memory)

1) 直接内存并不在Java虚拟机规范中,不是Java的一部分,但是也被频繁使用并可能导致OutOfMemoryError。
2) Native函数库可以直接分配堆外内存,通过存储在Java堆里的DirectDataBuffer对象作为这块内存的引用进行操作。这样做在一些场景中可以显著提高性能。
3) 直接内存是堆外内存,自然不受Java堆大小的限制,但是可能受实体机内存大小的限制。如果内存各部分总和大于实体机的内存时,也会报出OutOfMemoryError。

10.Java垃圾回收

1) 将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器
2) 由于GC需要消耗一些资源和时间,Java在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停。
3) 不同的对象引用类型, GC会采用不同的方法进行回收:
	   强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用,GC时才会被回收)。
	   软引用:软引用是Java中提供的一种比较适合于缓存场景的应用(只有在内存不够用的情况下才会被GC)。
	   弱引用:在GC时一定会被GC回收。
	   虚引用:由于虚引用只是用来得知对象是否被GC。

11.JVM线程与原生线程的关系

1) JVM允许一个程序使用多个并发线程,Hotspot JVM中Java的线程与原生操作系统的线程是直接映射关系。
2) 即当线程本地存储、缓冲区分配、同步对象、栈、程序计数器等准备好以后,就会创建一个操作系统原生线程。
3) Java 线程结束,原生线程随之被回收。
4) 操作系统负责调度所有线程,并把它们分配到任何可用的 CPU 上。
5) 当原生线程初始化完毕,就会调用 Java 线程的 run() 方法。
6) run() 返回时,被处理未捕获异常,原生线程将确认由于它的结束是否要终止 JVM 进程(比如这个线程是最后一个非守护线程)
7) 当线程结束时,会释放原生线程和 Java 线程的所有资源。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值