jvm虚拟机的简单理解

jvm虚拟机内存模型组成部分有三大组成部分:
1)类装载子系统
2)运行时数据区:堆,栈(线程),本地方法栈,方法区,程序计数器
3)执行引擎

1.类装载子系统

  在JAVA虚拟机中,负责查找并装载类型的那部分被称为类装载子系统。
  类装载器子系统除了要定位和导入二进制class文件外,还必须负责验证被导入类的正确性,为类变量分配并初始化内存,以及帮助解析符号引用。这些动作必须严格按以下顺序进行:
(1)装载——查找并装载类型的二进制数据。
(2)连接——指向验证、准备、以及解析(可选)。

  • 验证:确保被导入类型的正确性。(java可以自定义安全策略等)
  • 准备:为类变量分配内存,并将其初始化为默认值。(这里的准备 和下面的初始化的顺序问题体现在java初始化中值变化的各种陷阱)
  • 解析:把类型中的符号引用转换为直接引用。

(3)初始化——把类变量初始化为正确初始值。(准备的时候设为默认值,此时才会正式给变量赋值)
  简单来讲类装载子系统是用来识别字节码class文件,一次来确定类的类型。

2.运行时数据区(内存模型)

内存模型有:堆,栈(线程),本地方法栈,方法区,程序计数器。

2.1堆

  堆:jvm的堆内存主要存储对象,垃圾收集器就是收集这些对象,然后根据GC算法回收。以及利用分代概念将堆内存划分为堆内存分为年轻代(Young Generation)、老年代(Old Generation)。年轻代又分为Eden和Survivor区Survivor区由FromSpace和ToSpace组成。Eden区占大容量,Survivor两个区占小容量,默认比例是8:1:1。jvm中还有一个非堆内存,属于永久代。
分代概念
  新生成的对象首先放到年轻代Eden区,当Eden空间满了,触发Minor GC,存活下来的对象移动到Survivor0区,Survivor0区满后触发执行Minor GC,Survivor0区存活对象移动到Suvivor1区,这样保证了一段时间内总有一个survivor区为空。经过多次Minor GC仍然存活的对象移动到老年代。
  老年代存储长期存活的对象,占满时会触发Major GC=Full GC,GC期间会停止所有线程等待GC完成,所以对响应要求高的应用尽量减少发生Major GC,避免响应超时。
Minor GC : 清理年轻代
Major GC : 清理老年代
Full GC : 清理整个堆空间,包括年轻代和永久代
所有GC都会停止应用所有线程。
分代的用处
  将对象根据存活概率进行分类,对存活时间长的对象,放到固定区,从而减少扫描垃圾时间及GC频率。针对分类进行不同的垃圾回收算法,对算法扬长避短。
为什么survivor分为两块相等大小的幸存空间?
  主要为了解决碎片化。如果内存碎片化严重,也就是两个对象占用不连续的内存,已有的连续内存不够新对象存放,就会触发GC。

2.2栈(线程)

  栈:java虚拟机中的栈主要储存的是基本数据类型和堆中对象的引用,这里的栈也可以称为线程栈,在每一个新线程启动时java虚拟机都会分配内存作为栈线程,Java栈以帧为单位保存线程的运行状态,即栈帧。
  某个线程正在执行的方法被称为该线程的当前方法,当前方法使用的栈帧称为当前帧,当前方法所属的类称为当前类,当前类的常量池称为当前常量池。在线程执行一个方法时,它会跟踪当前类和当前常量池。此外,当虚拟机遇到栈内操作指令时,它对当前帧内数据执行操作。
  每当线程调用一个Java方法时,虚拟机都会在该线程的Java栈中压入一个新帧。而这个新帧自然就成为了当前帧。在执行这个方法时,它使用这个帧来存储参数、局部变量、中间运算结果等数据。
  Java方法可以以两种方式完成。一种通过return返回的,称为正常返回;一种是通过抛出异常而异常终止的。不管以哪种方式返回,虚拟机都会将当前帧弹出Java栈然后释放掉,这样上一个方法的帧就成为当前帧了。
  Java帧上的所有数据都是此线程私有的。任何线程都不能访问另一个线程的栈数据,因此我们不需要考虑多线程情况下栈数据的访问同步问题。当一个线程调用一个方法时,方法的的局部变量保存在调用线程Java栈的帧中。只有一个线程能总是访问那些局部变量,即调用方法的线程。
栈帧:
  栈帧中的内存分配为:局部变量表,操作数栈,动态链接,方法出口。每一个栈帧都有一个方法出口,我们可以将栈帧理解为局部方法线程栈。

2.3.本地方法栈

  java语言中若需要调用C语言或者c++语言实现系统的方法时,调用的方法则保存在本地方法栈中,包括一些局部变量,操作数栈等内存分配。

2.4方法区(元空间)

  元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小。
  方法区也是所有线程共享。主要用于存储类的信息、常量池、方法数据、方法代码等。

2.5程序计数器

  程序计数器标识执行程序的当前代码位置,每一行代码的行号,运行的每一个线程都有独有的程序计数器。

3.执行引擎

  类装载器装载负责装载编译后的字节码,并加载到运行时数据区(Runtime Data Area),然后执行引擎会执行这些字节码。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值