JVM-2 运行时数据区

运行时数据区

在这里插入图片描述

程序执行时:

​ 每个线程独立的拥有 程序计数器、本地方法栈、虚拟机栈

​ 线程共享:方法区和堆空间

程序计数器(pc寄存器)

作用:

​ pc寄存器用于存储下一条指令的地址,即将要执行的指令代码,由执行引擎读取下一条指令

常见问题

​ 1、为什么使用PC寄存器记录当前线程的执行地址?

​ 答:因为CPU需要不停的切换各个线程,切换一个线程后需要记录下次执行从哪开始。明确下次开始的地址

​ 2、 PC寄存器为什么被设定为每个线程一份

​ 答:因为每个线程是独立的,cpu执行时并发的执行多线程,切换时需要记录每个线程执行的地址。

虚拟机栈

Java的指令是基于栈的架构

栈是运行时单位,而堆是存储单位

作用:

​ 主管JAVA程序的运行,它保存方法的局部变量,部分结果,并参与方法的调用和返回。

JVM对栈的操作只有出栈和压栈。且允许Java栈的大小是动态的或是固定不变的。

对于栈来说不存在垃圾回收,但存在异常

栈可能的异常

1、StackOverFlowError

​ 当固定栈的容量时,线程请求分配的栈容量超过Java虚拟机栈允许的最大容量。

2、OutofMemoryError

​ 虚拟机的栈容量是可变时,尝试扩展内存但无法申请额外内存。

设置栈大小命令:`-Xss

​ 在运行时的 VMoptions

栈内部的存储单位

每个线程都有自己的栈,栈中的数据都是以栈帧的形式存在。

在这个线程上执行的每个方法都对应着一个栈帧,

栈运行原理

​ 1、不同线程中所包含的栈帧是不允许存在相互引用的,即不能在一个栈帧中引用另一个线程的栈帧。

​ 2、Java方法有两种返回方式:一种是正常的return 返回,一种是抛出异常。这两种都会导致方法栈帧被弹出

栈帧的内部结构

1、局部变量表

定义:一个数字数组,主要存储方法参数和定义在方法内部的局部变量

特点:

局部变量表不涉及安全问题

局部变量表所需要的容量在编译器就确定了

局部变量表的基本存储单元是槽(Slot)

32位以内的类型占用一个槽:

64位的类型占用两个操:long double

补充说明:

​ 局部变量表中的变量是重要的垃圾回收根节点。

2、操作数栈(表达式栈)

​ 在执行方法过程中,根据字节码指令,往栈中写入数据或提取数据。

理解为方法执行过程中的一个个指令执行的临时数据

​ 栈顶缓存技术:将栈顶元素全部缓存在物理cpu寄存器中,降低对物理内存的读写

3、动态链接(指向运行时常量池的方法引用)

​ 每个栈帧内部包含一个指向运行时常量池中该栈帧所属方法的引用

静态链接:当目标调用的方法在编译期间确定并始终保持不变时,调用的过程称之为静态链接

动态链接:当目标调用的方法在编译期间不能确定(接口),调用的过程称之为动态链接。

方法的调用分类

非虚方法:在编译期确定的方法。

虚方法:在编译器不能确定的方法。

4、方法返回地址

存放该方法pc寄存器的值

5、一些附加信息

可有可无

本地方法栈

介绍本地方法栈之前,需要介绍本地方法区

本地方法区

一个native method 就是一个Java调用非Java方法的接口

本地方法栈用于管理本地方法的调用。

其错误与虚拟机栈一致。

堆是每个线程共有的部分,是进程中的唯一。每个JVM实例只能有一个堆

堆中存放的几乎都是对象和数组。栈帧内部的局部变量表存放的就是指向对象或数组的引用。

在方法结束后,堆中的对象不会立即被移除,仅仅在垃圾收集时才会被移除。

堆是GC(垃圾回收)重点对象。

堆的内存结构

在这里插入图片描述

设置堆大小指令:

​ -Xms :表示堆区(新生区和老年区)的起始内存大小

​ -Xmx :表示堆区(新生代老年代)设置的最大内存

堆区的默认起始内存大小为物理内存的1/64,最大内存为物理内存的1/4。

**出错:**OOM:OutOfMemory 内存满了

新生代与老年代

其中新生代又可以被划分为Eden(伊甸园)空间、S0和S1区。
在这里插入图片描述

配置新生代老年代在堆结构的占比(一般不修改)

默认-XX:NewRatio=2,表示新生代占1、老年代占2、新生代占整个堆的1/3.

几乎所有的Java对象都是在Eden区被new出来的

对象分配过程

在这里插入图片描述在这里插入图片描述

YGC:又称minor GC,是垃圾回收器的一种。回收Eden区和幸存者区

堆中的垃圾回收

频繁在新生区回收,很少在老年区回收,几乎不再永久区/元空间回收。

堆中的几个垃圾回收

1、Minor GC

​ 针对于新生区的垃圾回收

2、Major GC

​ 针对 老年区进行垃圾回收

3、Full GC

​ 整堆收集,收集整个Java堆和方法区的垃圾收集

方法区

尽管所有的方法区在逻辑上属于堆的一部分,但具体的实现上与堆分开。

方法区与堆一样,是线程共享的内存结构

针对于HotSpot 虚拟机而言。

JDK 1.7 以前 方法区叫做 永久代

JDK 1.8 以后 方法区叫做 元空间

使用本地内存中实现了元空间,不在占用虚拟机内存。增加

方法区的内部结构

在这里插入图片描述

方法区存储已被虚拟机加载的类型信息、常量、静态变量、即时编译后的代码缓存

类型信息

类的全限定类名

类型的直接父类的完整有效名

类的修饰符

类型直接接口的一个有序列表

类的内部属性

类的方法信息

运行时常量池

常量池:class文件中包含了常量池。常量池包含各种字面量和对类型、域和方法的符号引用。

为什么需要一个常量池呢?

将类中的各种信息以符号引用存储,运行时,加载符号对应的信息。减少class文件的大小

运行时常量池是方法区的一部分,常量池通过类加载器加载到方法区后,称为运行时常量池的引用。

其特点是具有 动态性

方法区的演变

1、首先明确,只有hotspot虚拟机才有永久代

2、hotspot虚拟机方法区的变化

  • jdk 1.6 及以前:有永久代,静态变量存放在永久代上

  • jdk 1.7 :有永久代,但已经逐步“去永久代”,字符串常量池、静态变量移除保存在堆中。

  • jdk 1.8 :无永久代,类型信息、字段、方法、常量保存在本地内存中,但是字符串常量池、静态变量仍保存在堆中。

方法区的垃圾回收

Java虚拟机规范中对方法区的垃圾回收是比较宽松的

方法区的垃圾回收主要针对两个部分:常量池中废弃的常量和不再使用的类型

常量池:当常量池的常量不用时,回收不再使用的类型:
1、该类所有的实例已经被回收

​ 2、该类的类加载器已经被回收

​ 3、该类对应的Java.lang.Class 对象在任何地方没有被引用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值