Java笔记-JVM初识
创始人
2024-05-25 11:26:09

1、JVM

1.1 JVM内存结构

JDK7内存模型

在这里插入图片描述

JDK8内存模型

在这里插入图片描述

JVM内存结构:

其中线程私有的是(1)(2)(3)

(1)PC寄存器(程序计数器):

a.每个线程都有,为了在多线程切换时,回到自己之前的位置
b.寄存器里边指定了下一条需要执行的指令
c.执行Java代码时,保存当前指令的地址
d.不会有OOM的情况
e.native方法为空

(2)Java虚拟机栈

1.每个方法执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈和出栈的过程。
2. 之前我们一直讲的栈区域实际上就是此处的虚拟机栈,再详细一点,是虚拟机栈中的局部变量表部分。
3.此区域一共会产生以下两种异常:
1. 如果线程请求的栈深度大于虚拟机所允许的深度(-Xss设置栈容量),将会抛出StackOverFlowError异常。
2. 虚拟机在动态扩展时无法申请到足够的内存,会抛出OOM(OutOfMemoryError)异常

每个方法执行时创建一个栈帧用于存储:
a.局部变量表:8种基本数据类型、对象引用、字节码指令地址。内存在编译期间分配
b.操作数栈:从局部变量种去除数据,深度在编译期间确定
c.动态链接:符号引用
d.方法返回地址:方法出口

(3)本地方法栈

与虚拟机栈作用一样,区别是本地方法栈执行Native方法,而虚拟机栈
为JVM执行的Java方法服务。

线程共享区域(4)(5)

(4)Java堆

a.在JVM启动时创建,所有的对象实例以及数组都要在堆上分配。
b.如果在堆中没有足够的内存完成实例分配并且堆也无法再拓展时,将会抛出OOM。
c.可以动态扩展OOM(年轻代、老年代、永久代-元空间)

(5)方法区/元数据区

a.用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
b.此区域的内存回收主要是针对常量池的回收以及对类型的卸载。当方法区无法满足内存分配需求时,将抛出OOM异常。

(6)运行时常量池-方法区内

a.编译期及运行期间产生的常量被放在运行时常量池中。
b.这里所说的常量包括:基本类型、包装类(包装类不管理浮点型,整形只会管理-128到127)和String。
c.类加载时,会查询字符串常量池,以保证运行时常量池所引用的字符串与字符串常量池中是一致的。

常量池补充说明
常量池可以分为 Class文件常量池、运行时常量池、字符串常量池:


a.Class文件常量池Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。b.运行时常量池运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。c.字符串常量池存储字符串对象,或是字符串对象的引用。

(7)直接内存

a.在JDK 1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。b.直接内存的分配不会受到Java堆大小的限制,但是,既然是内存,肯定还是会受到本机总内存(包括RAM以及SWAP区或者分页文件)大小以及处理器寻址空间的限制。也可能导致OutOfMemoryError异常出现。

1.2 JVM垃圾回收机制GC

**JVM垃圾回收发生在堆和方法区,Java进程在启动后会创建垃圾回收线程,来对内存中无用的对象进行回收。
**

1.2.1 如何判断对象已死(垃圾)

(1)引用计数法

给对象分配一个引用计数器,每当有地方引用它时,计数+1,当引用失效时,计数-1。当某个对象的计数为0时,就不能被引用了,人认为对象已死。
缺点:当两个对象循环引用时,无法回收

(2)可达性分析法

任务所有对象都是从“GC Roots”的对象作为起始点(树根节点),从这些节点出发向下搜索,可以遍历到的对象就是“可达对象”,遍历的路径称为“GC Roots引用链”。当某个对象与GC Roots之间没有引用链时,就认为该对象不可达,这些对象会被认为是可以回收的对象
在这里插入图片描述

1.2.2 垃圾回收算法

(1)复制引用法-新生代的收集算法

将内存分为容量相等的两块,每次只使用其中一块,当这一块用完了,就将还活着的对象复制到另外一块上,然后把已使用的内存空间一次性清理掉
优点:实现简单,因为每次都是堆整个半区进行回收,因此就不会产生内存碎片
缺点:内存利用率低,只能用一半

(2)标记清除法-老年代收集算法(基础算法)

(1)先标记出要回收的对象
(2)标记完成后,统一回收这些对象
优点:不需要额外的空间
缺点:回产生内存碎片

(3)标记整理法-老年代收集算法

(1)先标记出要回收的对象
(2)标记完成后,统一回收这些对象
(3)让存活的对象向一端移动

(4)分代收集算法

  • 当前JVM垃圾收集都采用的是"分代收集(Generational Collection)"算法,这个算法并没有新思想,只是根据对象存活周期的不同将内存划分为几块。
  • 一般是把Java堆分为新生代和老年代。
  • 在新生代中,每次垃圾回收都有大批对象死去,只有少量存活,因此我们采用复制算法;而老年代中对象存活率高、没有额外空间对它进行分配担保,就必须采用"标记-清理"或者"标记-整理"算法。

2、堆和方法区的垃圾回收

3、Java8中字符串常量池到底是在哪里?

今天看String\StringBuilder\StringBuffer时,遇到了字符串常量池这个名词,虽然之前听过,但没有细究过它到底是存在哪里。
于是在网上搜寻了一番,说的我都挺懵,但看到一篇自我感觉比较清晰详细的文章,在这里–》


总的来说就是,JDK1.7之前,运行时常量池(字符串常量池也在里边)是存放在方法区,此时方法区的实现是永久带。
JDK1.7字符串常量池被单独从方法区移到堆中,运行时常量池剩下的还在永久带(方法区)
JDK1.8,永久带更名为元空间(方法区的新的实现),但字符串常量池池还在堆中,运行时常量池在元空间(方法区)。

相关内容

热门资讯

苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...