JVM结构及内存管理

了解JVM

JVM,即Java虚拟机,主要负责将编译器编译产生的字节码文件(.class)解释成机器码,然后通过机器码调用操作系统的本地方法库,完成相应的操作。
同时,java程序在运行过程中的内存管理也是由JVM负责的。

JVM的结构

在这里插入图片描述

JVM包含:类加载子系统、运行时数据区(运行时管理的内存区域)、执行引擎和本地接口库。

类加载子系统:

主要负责将编译器编译好的.Class文件加载到JVM中,实现类的加载、连接和初始化等工作。

方法区:

线程共享区域,主要存放:
1、虚拟机已加载的类信息,包括版本、字段、方法、接口等;
2、运行时常量池;
3、类的静态变量(JDK 1.7开始转移到堆内存);
4、即时编译器编译后的代码缓存。

运行时常量池与class常量池:
.Class文件中除了类信息外,还有一个常量池表,称为class常量池或静态常量池,用于存放编译器生成的各种字面量和符号引用;
字面量:通过字面就能理解的常量概念。包括:1.文本字符串,如"hello"; 2.基本数据类型的值,如1、2; 3.被声明为final的常量等;
符号引用:与直接引用相对,在目标实际内存地址未知时,用一组符号来表示其引用。内容包括:1.类和方法的全限定名;2.字段的名称和描述符;3.方法的名称和描述符。
直接引用:可以是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄,能够明确定位到目标在内存中的地址。
JVM类加载过程中,会将class常量池的内容保存到运行时常量池中,并将符号引用替换为直接引用。
相比class常量池,运行时常量池具有动态性,即使是程序运行阶段,也可能有新的常量加入运行时常量池。
字符串常量池:
JDK 1.7之前,字符串常量池在逻辑上属于运行时常量池的一部分,存在于方法区;不同的是,字符串常量池全局唯一,而运行时常量池每个类各有一份。
JDK 1.7中,HopSpot JVM开始去"永久代",将字符串常量池和静态变量从永久代转移到了堆内存中。(JDK 1.7及以前的方法区是由永久代实现的,永久代逻辑上是"非堆"的,但物理上却是一块连续的堆内存)
JDK 1.8开始,完全移除了"永久代",并使用元空间来代替。元空间是方法区的实现,使用本地内存,而非JVM内存。
为什么使用元空间替换掉永久代?
1)永久代经常因为空间不足,抛出OutOfMemoryError,即内存溢出;
2)为了促进与其他无"永久代"JVM产品的融合,如JRockit VM;
3)简化FullGC的过程。

堆主要用来存放对象实例,比如通过new创建出来的对象;堆是所有线程共享的区域,也是垃圾回收的重点区域。

虚拟机栈

线程私有区域,每个线程独占一个栈空间,该栈与线程具有相同的生命周期。
栈主要用来实现方法的调用和执行,每个方法执行时,虚拟机都会创建一个"栈帧"来保存方法的局部变量表、操作数栈、动态链接和方法出口等信息;一个方法的调用和结束,对应的是其栈帧的入栈和出栈。

本地方法栈

线程私有,虚拟机调用Native方法时,使用本地方法栈。
Native方法:即本地方法,由非Java语言编写,编译后保存在动态链接库文件中,用于与操作系统进行交互。

程序计数器

线程私有,可以看做当前线程所执行的字节码的行号指示器,解释器就是通过改变程序计数器的值来确定下一条需要被执行的字节码指令,从而控制程序运行的流程。

执行引擎

执行引擎包含了解释器、即时编译器(JIT)和垃圾回收器。
解释器:逐行地将字节码解释成机器指令,并立即交由CPU执行,即解释一行执行一行。
即时编译器:为了避免函数体被解释执行,即时编译器将整个函数体编译成机器码指令,每次函数执行时,只执行编译后的机器码即可,这种方式可以大大提高效率。
解释器和即时编译器可以通过相互协作,共同完成字节码到机器指令的转化。

本地接口库

用来调用操作系统的本地方法库,实现相关操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值