《深入理解JAVA虚拟机》学习笔记

news2025/1/23 2:08:26
1.java内存结构,以及每个结构的作用?
  • 线程共享区

      堆内存:所有的对象实例都要在堆上分配
      
      方法区:是各个线程共享的内存区域,
      
      它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
    
  • 非线程共享区

      Java虚拟机栈:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息
      
      本地方法栈:虚拟机调用本地方法的区域
      
      程序计数器:当前线程所执行的字节码的行号指示器
    

java1.8:

以后在JDK1.8中元空间区取代了永久代,永久代原本主要存放Class和Meta的信息。

而元空间的本质和永久代类似,都是对JVM规范中方法区的实现。

不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。

因此,默认情况下,元空间的大小仅受本地内存限制。

2.什么是java垃圾回收机制?

java内存是有限的,需要不定时去回收不可达的对象,如果不进行垃圾回收,

内存迟早会被消耗空。

3.垃圾回收的过程,以堆内存结构去分析?

新生代(1/3) 老年代(2/3)

新生代分为:Eden伊甸园、from(s0)、to(s1)

​ (8/10) (1/10) (1/10)

1).判断哪些对象是垃圾

2).垃圾回收算法

4.如何判断对象是否存活?
  • 引用计数法:

      如果一个对象没有被任何引用指向,则可视之为垃圾。这种方法的缺点就是不能检测到环的存在。
      
      首先需要声明,至少主流的Java虚拟机里面都没有选用引用计数算法来管理内存。 
      
      什么是引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,
      
      计数器值加1;当引用失效时,计数器值减1.任何时刻计数器值为0的对象就是不可能再被使用的。
      
      那为什么主流的Java虚拟机里面都没有选用这种算法呢?
      
      其中最主要的原因是它很难解决对象之间相互循环引用的问题
    
  • 根搜索算法:

      根搜索算法的基本思路就是通过一系列名为”GC Roots”的对象作为起始点,
      
      从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),
      
      当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
      
      那么问题又来了,如何选取GCRoots对象呢?在Java语言中,可以作为GCRoots的对象包括下面几种:
      
      (1). 虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象。
      
      (2). 方法区中的类静态属性引用的对象。
      
      (3). 方法区中常量引用的对象。
      
      (4). 本地方法栈中JNI(Native方法)引用的对象。
      
      下面给出一个GCRoots的例子,如下图,为GCRoots的引用链。
    

img

img

5.有哪些垃圾回收算法?
  • (1).标记-清除:

应用场景:

该算法一般应用于老年代,因为老年代的对象生命周期比较长。

该算法有两个阶段。

  1. 标记阶段:找到所有可访问的对象,做个标记

  2. 清除阶段:遍历堆,把未被标记的对象回收

优点:

是可以解决循环引用的问题

必要时才回收(内存不足时)

缺点:

标记和清除的效率不高,尤其是要扫描,尤其是要扫描的对象比较多的时候

会造成内存碎片(会导致明明有内存空间,但是由于不连续,申请稍微大一些的对象无法做到)

  • (2).复制算法:

复制算法一般使用在新生代中,因为新生代中的对象一般都是朝生夕死,存活的对象并不多,

这样使用coping算法进行拷贝时效率高。

如果jvm使用了cpying算法,一开始就会将可用内存分为两块,from(s0)域和to(s1)域,

每次只是使用from域,to域则空闲着。当from域内存不够了,开始执行GC操作,这个时候,

会把from域存活的对象拷贝到to域,然后直接把from域进行清理

步骤:1.当Eden区满的时候会触发第一个young gc,把还活着的对象拷贝到From;

当Eden区再次触发young gc的时候,会扫描Eden区和From区域,对两个区域进行垃圾回收,

经过这次回收后还存活的对象,直接复制到To区域,并将Eden和From区域清空。

2.当后续Eden又发生young gc的时候,会对Eden和To区域进行垃圾回收,存活的对象复制到From区域,

并将Eden和To区域清空。

3.可见部分对象会在From和To区域中复制来复制去,如此交换15次(由jvm参数MaxTenuringThreshold决定,

这个参数默认值是15),最终如果还是存活,就存入到老年代。

注意!!!:万一存活对象比较多,那么To域的内存可能不够存放,这个时候会借助老年代的空间。

优点:在存活对象不多的情况下,性能高,能解决内存碎片和标记清除算法中导致更新的问题。

缺点:会造成一部分内存浪费,因为有一部分内存是空的,不过可以根据实际情况,将内存块大小

比例适当调整;如果存活对象的数量比较大,coping的性能会变得很差。

  • (3).标记-压缩算法:

标记清除算法和标记压缩算法非常相同,

但是标记压缩算法在标记清除算法之上解决内存碎片化

优点:解决内存碎片问题

缺点:压缩阶段,由于移动了可用对象,需要去更新引用。

  • (4).分代算法:

当前商业虚拟机的GC都是采用的’分代收集算法’,这并不是什么新的思想,只是根据对象的

存活周期的不同将内存划分为几块儿。

少量对象存活,适合复制算法,一般用在新生代

大量对象存活,适用于标记整理算法/标记清除算法

6.Minor GC和MajorGC、Full GC区别

年轻代满时会触发Minor GC,这里的年轻代满是指Eden区满。

老年代满时会触发MajorGC,只有CMS收集器会有单独收集老年代的行为,其他收集器均无此行为。

FullGC是针对新生代,老年代和方法区(元空间)的垃圾收集。FullGC产生的条件:

(1)调用System.gc时,系统建议执行Full GC,但是不一定会执行 。

(2)老年代空间不足。

(3)方法区空间不足,类卸载(类卸载三个条件)。

(4)通过 Minor GC 后进入老年代的空间大于老年代的可用内存

(5)内存空间担保。

7.JVM会在永久代中发生垃圾回收吗?

垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。

如果你仔细查看垃圾回收器的输出信息,就会发现永久代也是被回收的。这就是为什么正确的

永久代大小对避免Full GC是非常重要的原因。(注意:java8中已经移除了永久代,新加了一个叫元数据区的

native内存区)

8.OutOfMemoryError异常如何解决?
  • java堆溢出

错误原因:java.lang.OutOfMemoryError: Java heap space 堆内存溢出

解决办法:设置堆内存大小 // -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

  • 虚拟机栈溢出

错误原因:java.lang.StackOverflowError 栈内存溢出

栈溢出 产生于递归调用,循环遍历是不会的,但是循环方法里面产生递归调用,也会发生栈溢出。

解决办法:设置线程的最大深度调用

-Xss5m 设置最大调用深度

9.内存溢出和内存泄露的区别?
  • 内存溢出(Out Of Memory) :就是申请内存时,JVM没有足够的内存空间。通俗说法就是去蹲坑发现坑位满了。
  • 内存泄露 (Memory Leak):就是申请了内存,但是没有释放,导致内存空间浪费。通俗说法就是有人占着茅坑不拉屎。
10.有哪些常用的垃圾回收器?

serial串行收集器、ParNew收集器、parallel收集器、cms收集器、g1收集器

11.jvm调优思路?

初始堆值和最大堆内存内存越大,吞吐量就越高。

最好使用并行收集器,因为并行收集器速度比串行吞吐量高,速度快。

设置堆内存新生代的比例和老年代的比例最好为1:2或者1:3。

减少GC对老年代的回收。

12.类加载的过程?

一个类从加载到内存开始,一直到被卸载结束,它的整个生命周期包括加载,连接

加载—>验证—>准备—>解析—>初始化—>使用—>卸载

​ <------连接Linking---->

img

加载(Load):类加载过程的一个阶段,ClassLoader通过一个类的完全限定名查找此类字节码文件,

并利用字节码文件创建一个class对象

验证(Verify):目的在于确保class文件的字节流中包含符合当前虚拟机要求,不会危害虚拟机自身的安全,主要包括四种验证:文件格式的验证,元数据的验证,字节码验证,符号引用验证。

验证一个Class的二进制内容是否合法

准备(Prepare):

在准备阶段,虚拟机会在方法区中为Class分配内存,并设置static成员变量的初始值为默认值.

注意这里仅仅会为static变量分配内存(static变量在方法区中),并且初始化static变量的值为其所属类型的默认值.如:int类型初始化为0,引用类型初始化为null.即使声明了这样一个static变量:

​ public static int a=123;

在准备阶段后,a在内存中的值仍然是0,赋值123这个操作会在中初始化阶段执行,因此在初始化阶段产生了对应的Class对象之后a的值才是123.

解析(Resolve):解析阶段,虚拟机会将常量池中的符号引用替换为直接引用,解析主要针对的是类,接口,方法,成员变量等符号引用. 在转换成直接引用后,会触发校验阶段的符号引用验证,验证转换之后的直接引用是否能找到对应的类,方法,成员变量等. 这里也可见类加载的各个阶段在实际过程中,可能是交错执行.

初始化(Initialize):初始化阶段是类加载过程的最后一步,这个阶段才开始的真正的执行用户定义的java程序.在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则需要为类变量(非final修饰的变量)和其他变量赋值,其实就是执行类的()方法.

初始化阶段即开始在内存中构造一个Class对象来表示该类,即执行类构造器()的过程。

13.双亲委派模式?

img

img

上图是上面所介绍的这几种类加载器的层次关系,称为类加载器的双亲委派模型.

该模型要求除了顶层的启动类加载器外,其他的类加载器都要有自己的父类加载器.

一言概之,双亲委派模型,其实就是一种类加载的层次关系.

工作过程:

如果一个类加载器收到了类加载的请求,它首先不会自己区尝试加载这个类,而是把这个委派给

加载器去完成,每一个层次的类加载器都是如此.

因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需要的类)时,子类加载器才会尝试去加载.

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次

14.双亲委派模式优势

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。可能你会想,如果我们在classpath路径下自定义一个名为java.lang.SingleInterge类(该类是胡编的)呢?该类并不存在java.lang中,经过双亲委托模式,传递到启动类加载器中,由于父类加载器路径下并没有该类,所以不会加载,将反向委托给子类加载器加载,最终会通过系统类加载器加载该类。但是这样做是不允许,因为java.lang是核心API包,需要访问权限,强制加载将会报出如下异常

15.线上如何去排查分析内存溢出的问题?

设置虚拟机参数生成堆内存dump日志文件—>使用分析工具去分析具体线程所占用的内存—>分析具体的数据结构代码—>分析代码—>修改紧急上线

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1347411.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

25、商城系统(七):商城项目基础功能pom.xml(重要),mybatis分页插件

截止这一章,我们就不把重心放在前端,后台的基础代码,因为后面都是业务层面的crud。 前端直接替换这两个文件夹即可,后台代码也直接复制: 一、重新更新一下所有的pom.xml 这个地方我踩了好多坑,最后得到一个完整的pom.xml,建议大家直接用我的pom.xml替换即可。 1.comm…

计算机组成原理知识总结

目录 第一章、计算机系统概述知识框架&#xff1a;1.冯诺依曼机和存储程序的概念&#xff1f;2.计算机的工作过程&#xff1f;3.在计算机系统结构中&#xff0c;什么是编译&#xff1f;什么是解释&#xff1f;4.描述一下指令执行过程&#xff1f;1) 取指令&#xff1a; PC 一&g…

[Angular] 笔记 25:指令

组件指令 (chatgpt 回答) 在 Angular 中&#xff0c;组件本身可以被视为指令&#xff0c;这种指令被称为组件指令。组件是 Angular 应用的构建块之一&#xff0c;它封装了一段具有特定功能和特性的用户界面&#xff0c;并且可以在应用中重复使用。 组件指令具有以下特征&…

图片预览 element-plus 带页码

vue3、element-plus项目中&#xff0c;点击预览图片&#xff0c;并显示页码效果如图 安装 | Element Plus <div class"image__preview"><el-imagestyle"width: 100px; height: 100px":src"imgListArr[0]":zoom-rate"1.2":max…

系列十五(面试)、RocketMQ消息重复消费问题

一、RocketMQ消息重复消费问题 1.1、官网 1.2、消息重复被消费原因 通过上述官网的描述我们可以知道&#xff0c;RocketMQ中的消息是存在重复消费的情况的。那么消息为什么会被重复消费呢&#xff1f;先来回顾一下RocketMQ的消息是怎么发送和接收的&#xff1a; 从上图可以看出…

Python入门学习篇(十四)——模块文件操作

1 模块 1.1 理解 包: python中带有__init__.py文件的文件夹 模块: 文件名(不包含.py后缀),如python官方的time.py中time就是模块1.2 示例代码 import datetime# 调用datetime模块中的datetime类的now()方法 t datetime.datetime.now() # 格式化输出日期和时间 strftime(&qu…

数据仓库【4】:最佳实践

数据仓库【4】&#xff1a;最佳实践 1、表的分类1.1、事实表1.2、维度表1.3、事务事实表1.4、周期快照事实表1.5、累积快照事实表1.6、拉链表 2、ETL策略2.1、全量同步2.2、增量同步 3、任务调度3.1、为什么需要任务调度&#xff1f;3.2、常见任务类型3.3、常见调度工具 1、表的…

类的加载顺序问题-demo展示

面试的的时候经常会被问到包含静态代码块、实例代码块和构造器等代码结构的加载顺序问题&#xff0c;下面借用一个面试题&#xff0c;回顾一下类的代码加载顺序。 public class AooTest {public static void main(String[] args) {AooTest.f1();}static AooTest test1 new Ao…

操作系统:分页存储管理方式

页式存储管理中&#xff0c;主存空间按页分配&#xff0c;可用一张“位示图”构成主存分配表。假设主存容量为2M字节&#xff0c;页面长度为512字节&#xff0c;若用字长为32位的字作主存分配的“位示图”需要多少个字&#xff1f;如页号从1开始&#xff0c;字号和字内位号&…

【Electron】富文本编辑器之文本粘贴

由于这个问题导致&#xff0c;从其他地方复制来的内容 粘贴发送之后都会多一个 换行 在发送的时候如果直接&#xff0c;发送innerHTML 就 可以解决 Electron h5 Andriod 都没问题&#xff0c;但是 公司的 IOS 端 不支持&#xff0c;且不提供支持&#xff08;做不了。&#xff…

让你的 Python 代码更快的 9 个技巧

在最近参加的一些技术会议上,我常常听到参会员在会中讨论技术选型时提到“Python太慢了”。然而,这种观点往往没有考虑到Python的众多优点。实际上,如果能够遵循Pythonic的编程风格,Python的运行速度可以非常快。这其中的关键在于掌握一些技术细节上的巧妙技巧。那些经验丰…

十大排序算法归纳

目录 排序算法的分类 插入排序算法模板 选择排序算法模板 冒泡排序算法模板 希尔排序算法模板 快速排序算法模板 归并排序算法模板 堆排序算法模板 基数排序算法模板 计算排序算法模板 桶排序算法模板 排序算法的分类 插入&#xff1a;插入&#xff0c;折半插入&am…

搭建普罗米修斯Prometheus,并监控MySQL

1.简介 prometheus是一种时间序列的数据库&#xff0c;适合应用于监控以及告警&#xff0c;但是不适合100%的准确计费&#xff0c;因为采集的数据不一定很准确&#xff0c;主要是作为监控以及收集内存、CPU、硬盘的数据。 Prometheus生态系统由多个组件组成&#xff0c;其中许…

【Java进阶篇】SimpleDateFormat是线程安全的吗? 使用时应该注意什么?

SimpleDateFormat是线程安全的吗?使用时应该注意什么? ✔️ 典型解析✔️拓展知识仓✔️SimpleDateFormat用法✔️日期和时间模式表达方法✔️输出不同时区的时间✔️SimpleDateFormat线程安全性✔️问题重现✔️线程不安全原因✔️如何解决✔️使用局部变量✔️加同步锁✔️…

基于YOLOv5+Deepsort 的PCB缺陷检测及计数系统

背景&#xff1a; PCB&#xff08;Printed Circuit Board&#xff0c;印刷电路板&#xff09;是电子产品中至关重要的组成部分&#xff0c;它承载着电子元器件并提供电气连接。在PCB制造过程中&#xff0c;由于工艺、材料或设备等因素的影响&#xff0c;可能会引入各种缺陷&am…

Seata AT TM->RC->RM一次完整的交互过程

原理 TM两阶段&#xff1a; 阶段1&#xff1a;TM向TC申请全局事务&#xff0c;netty客户端发起了一次记录xid的请求 阶段2&#xff1a;TC协调之后&#xff0c;决定执行RM是否提交或者回滚。 spring公共组件部分 1、SeataAutoConfiguration类 利用springboot自动装配机制从…

Java版商城:Spring Cloud+SpringBoot b2b2c电子商务平台,多商家入驻、直播带货及免 费 小程序商城搭建

随着互联网的快速发展&#xff0c;越来越多的企业开始注重数字化转型&#xff0c;以提升自身的竞争力和运营效率。在这个背景下&#xff0c;鸿鹄云商SAAS云产品应运而生&#xff0c;为企业提供了一种简单、高效、安全的数字化解决方案。 鸿鹄云商SAAS云产品是一种基于云计算的软…

【算法练习】leetcode链表算法题合集

链表总结 增加表头元素倒数节点&#xff0c;使用快慢指针环形链表&#xff08;快慢指针&#xff09;合并有序链表&#xff0c;归并排序LRU缓存 算法题 删除链表元素 删除链表中的节点 LeetCode237. 删除链表中的节点 复制后一个节点的值&#xff0c;删除后面的节点&#x…

多环境及SpringBoot项目部署

1、多环境 2、项目部署上线 原始前端 / 后端项目宝塔Linux容器容器平台 3、前后端联调 4、项目扩展和规划 多环境 程序员鱼皮-参考文章 本地开发&#xff1a;localhost&#xff08;127.0.0.1&#xff09; 多环境&#xff1a;指同一套项目代码在把不同的阶段需要根据实际…

【Vue2+3入门到实战】(17)VUE之VueCli脚手架自定认创建项目、ESlint代码规范与修复、 ESlint自动修正插件的使用 详细示例

目录 一、本节内容二、VueCli 自定义创建项目三、ESlint代码规范及手动修复1.JavaScript Standard Style 规范说明2.代码规范错误3.手动修正 四、通过eslint插件来实现自动修正 一、本节内容 VueCli脚手架自定认创建项目ESlint代码规范与修复ESlint自动修正插件 二、VueCli 自…