JVM篇--垃圾回收高频面试题

JVM垃圾回收

1 简单说下Java垃圾回收机制?

首先在java运行过程中,其实程序员并不需要去显示的调用程序来释放对象的内存,而是由虚拟机来完成的,具体来看是在jvm中有个垃圾回收线程,这个线程是个守护线程,这个线程会在虚拟机空闲或者在当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。

2 垃圾回收器的基本原理是什么?优点有哪些,垃圾回收器可以马上回收内存吗?

其实jvm的垃圾回收,在我们一开始创建对象的时候,GC就会去监控这个对象的地址,大小和使用情况,而jvm在进行回收的时候主要是采用了可达性分析算法,通过这种方式确定哪些对象是"可达
的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。
其实垃圾回收的优点也很明显,首先就是不用像其他语言一样需要程序员手动的去释放内存,其次垃圾回收机制可以有效的防止内存泄露,并且可以做到对内存进行更有效的利用
对于垃圾回收的时机,虽然程序员可以通过执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。

3 怎么判断对象是否可以被回收?

我们刚才说到jvm会自动的对内存进行回收,因此它在回收的时候就需要知道 哪些对象是存活的,不需要被回收;而哪些对象又是垃圾对象,可以被回收,那么它具体是怎么判断的呢?
其实有两种判断方式
1 引用计数法:说白了也就是会为每一个对象创建一个引用计数,有对象引用时,计数器会加1,而引用释放时计数器会减1,而当计数器为0时也就表示对象可以被回收,它有一个缺点就是不能解决循环引用的问题
2 可达性分析算法:也就是会从GC root开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。

4 JVM 运行时 堆内存如何分代?

Java 堆从 GC 的角度还可以细分为: 新生代和老年代。
而新生代 又可以分为 (Eden 区、 From Survivor 区和 To Survivor 区)
一般新生代和老年代的比例约为 1:2
同时 eden区:s1区:s2区约为 8:1:1
在这里插入图片描述
同时对于新生代来说 JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor区域是空闲着的。
整体的流程就是 :新建的对象会首先分配在Eden区中,经历一次Minor GC,Eden中的存活对象就会被移动到第一块survivor S0区,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor S1 区,就是通过这样不断地复制–>清空—>互换来实现年轻代的垃圾回收即minor gc
同时年轻代采用复制算法,也解决了内存碎片化的问题

我们接着再看老年代
老年代的对象特点 一般都是长生命周期的对象,也就是比较稳定,因此 MajorGC (常常称之为 FULL GC)不会频繁执行。
同时注意在进行 FULL GC前一般都先进行了一次 MinorGC,使得有新生代的对象晋身入老年代,导致空间不够用时才触发。当无法
找到足够大的连续空间分配给新创建的较大对象时也会提前触发一次 MajorGC 进行垃圾回收腾出空间。

FULL GC 采用标记清除算法,同时会产生内存碎片

永久代 (或者 jdk1.8元空间)
指内存的永久保存区域,主要存放 Class 和 Meta(元数据)的信息,Class 在被加载的时候被放入永久区域, 它和和存放实例的区域不同,GC 不会在主程序运行期对永久区域进行清理。所以这也导致了永久
代的区域会随着加载的 Class 的增多而胀满,最终抛出 OOM 异常。

5 JVM内存为什么要分成新生代,老年代,永久代(即为什么要分代)?新生代中为什么要分为Eden和Survivor?

这个问题 其实想一下就能理解 分代主要还是 为了提高对象内存分配和垃圾回收的效率。
试想一下,如果堆内存没有区域划分,所有的新创建的对象和生命周期很长的对象放在一起,随着程序的执行,堆内存需要频繁进行垃圾收集,而每次回收都要遍历所有的对象,遍历这些对象所花费的时间代价是巨大的,会严重影响我们的 GC 效率

而有了内存分代,情况就不同了,新创建的对象会在新生代中分配内存,经过多次回收仍然存活下来的对象存放在老年代中,
静态属性、类信息等存放在永久代(或者元空间)中,
新生代中的对象存活时间短,只需要在新生代区域中频繁进行 GC,老年代中对象生命周期长,内存回收的频率相对较低,不需要频繁进行回收。

而新生代为什么要分为eden区和survivor区 ?

  1. 我们试想下 如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。这样一来老年代很快被填满,触发Major GC.
    又因为老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多,
    所以总结来看 分为eden区 和s区可以减少对象频繁地被输送到老年代,进而减少了full gc的发生。
  2. 同时分为两个eden区,利用这种复制算法也避免了内存的碎片化。

6 JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代?

针对这个问题,思路就是可以先描述下java堆内存的划分,以及minor gc,major gc,full gc 以及他们之间的转换过程。
首先我们知道java堆可以分为 老年代 + 新生代;同时 新生代 = Eden + S0 + S1
整体的过程就是:

  1. 当 Eden 区的空间满了, Java虚拟机会触发一次 Minor GC,以收集新生代的垃圾,存活下来的对象,则会转移到 Survivor区
  2. 而 如果对象在Eden出生,并经过第一次Minor GC后仍然存活,并且被Survivor容纳的话,年龄设为1,每熬过一次Minor GC,年龄+1,若年龄超过一定限制(15)----即经过静态年龄判断规则后,则被晋升到老年态。即长期存活的对象进入老年态。
    当然对于大对象 (比如那种连续内存空间的java对象,比如那种很长的字符串)也会直接进入老年代
  3. 当老年代满了无法容纳更多的对象,就会发生major gc清理掉老年代,同时major gc会伴随着至少一次minor gc。
  4. 而Full GC 会清理整个内存堆 – 包括年轻代和年老代。

那么Minor GC与Full GC分别在什么时候发生?
新生代内存不够用时候发生minor gc也叫YGC;JVM内存不够的时候发生FGC

7 JVM 有哪些垃圾回收算法?

可以分为 四种,即标记-清除算法;复制算法;标记整理算法; 分代收集算法;
我们首先看标记清除算法
该算法分为“标记”和“清除”阶段:首先标记出所有不需要回收的对象,在标记完成后统一回收掉所有没有被标记的对象。
适用场合:存活对象较多的情况、适用于年老代。
优点:比较简单,不需要对象的移动
缺点:会产生大量的内存碎片;效率也比较低

复制算法
因为标记清除算法会产生内存碎片 因此在他的基础之上引入复制算法
说白了复制算法 就是 把内存空间划为两个相等的区域,每次只使用其中一个区域。
垃圾收集时,遍历当前使用的区域,把存活对象复制到另外一个区域中,最后将当前使用的区域的可回收的对象进行回收。
优点:按顺序分配内存即可,实现简单、运行高效,不用考虑内存碎片
缺点:可用的内存大小缩小为原来的一半,对象存活率高时会频繁进行复制。
在这里插入图片描述

标记整理算法
刚才说了复制算法 解决了内存碎片化的问题,但是它也有一个问题,就是内存的使用率并不高,需要频繁地进行来回复制,
因此又引入了标记整理算法,说白了 就是在标记可回收的对象后将所有存活的对象压缩到内存的一端,使他们紧凑的排列在一起,然后对端边界以外的内存进行回收。回收后,已用和未用的内存都各自一边。
优点是:解决了内存碎片化的问题,相比于复制算法 内存使用率也提高了
缺点:仍需要进行局部对象移动,一定程度上降低了效率
在这里插入图片描述
分代收集算法:
分代收集法是目前大部分 JVM 所采用的方法,顾名思义是根据对象的存活周期将内存划分为几块。一般包括年轻代、老年代 和 永久代,并根据各年代特点分别采用最适当的 GC 算法
老生代的特点是每次垃圾回收时只有少量对象需要被回收,
新生代的特点是每次垃圾回收时都有大量垃圾需要被回收,
因此可以根据不同区域选择不同的算法
在这里插入图片描述
新生代与复制算法
每次垃圾收集都能发现大批对象已死, 只有少量存活. 因此选用复制算法, 只需要付出少量存活对象的复制成本就可以完成收集,当然并不是按照1:1来划分新生代,一般是按照eden区,s1区,s2区 =8:1:1 来划分
老年代与标记整理算法
因为老年代对象存活率高、没有额外空间对它进行分配担保, 就必须采用“标记—清理”或“标记—整理” 算法来进行回收, 不必进行内存复制, 且直接腾出空闲内存。因而采用 标记整理算法。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pytest实现多进程与多线程运行超好用的插件

前言 如果想分布式执行用例,用例设计必须遵循以下原则: 1、用例之间都是独立的, 2、用例a不要去依赖用例b 3、用例执行没先后顺序, 4、随机都能执行每个用例都能独立运行成功每个用例都能重复运行,不影响其它用例 这…

假设检验:以样本服从二项分布举例

目录 假设检验一、假设检验的思想二、假设检验的基本步骤1. 确定要进行检验的假设2. 选择检验统计量。3. 确定用于做决策的拒绝域4. 求出检验统计量的值5. 查看样本结果是否位于拒绝域内6. 做出决策 三、举例说明例子1——某公司治疗打鼾例子2——女士品茶的故事 假设检验 一、…

python爬虫知识点:5种线程锁

嗨喽~大家好呀,这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 线程安全 线程安全是多线程或多进程编程中的一个概念,在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个…

细说JavaScript事件处理(JavaScript事件处理详解)

js语言的一个特色和就是它的动态性,即一时间驱动的方式对用户输入作出反应而不需要依赖服务器端程序。事件是指人机交互的结果,如鼠标移动、点击按钮、在表单中输入数据或载入新的Web洁面等。 一、什么是事件 1、事件类型 1.1、事件源 1.2、事件处理…

【数据结构】详谈队列的顺序存储及C语言实现

循环队列及其基本操作的C语言实现 前言一、队列的顺序存储1.1 队尾指针与队头指针1.2 基本操作实现的底层逻辑1.2.1 队列的创建与销毁1.2.2 队列的增加与删除1.2.3 队列的判空与判满1.2.4 逻辑的局限性 二、循环队列2.1 循环队列的实现逻辑一2.2 循环队列的实现逻辑二2.3 循环队…

Git 配置与理解

简述 Git 在 Windows 和 Ubuntu 中的配置,以及对 Git 工作区域划分和 Git 中对于文件状态划分的理解。 git 基础安装与配置 基于 WSL 的 Ubuntu 下的 git 打开或关闭Windows功能 -> Hyper-V、Virtual Machine Platform、Windows Subsystem for Linux # 1.必须…

傲空间私有部署Windows指南

推荐阅读 智能化校园:深入探讨云端管理系统设计与实现(一) 智能化校园:深入探讨云端管理系统设计与实现(二) 安装 docker 请下载对应的 Docker,安装完成后启动。 Docker Desktop for Windows…

【Linux取经路】初探进程地址空间

文章目录 一、历史问题回顾二、语言层面的地址空间2.1 验证 三、虚拟地址的引入3.1 初步解释这种现象——引入地址空间的概念3.2 再来粗粒度理解上面的现象 四、细节解释4.1 地址空间究竟是什么?4.2为什么要有地址空间4.3 页表4.3.1 CR3寄存器4.3.2 页表是由页表项组…

智慧校园大数据应用系统介(3)

智能巡课系统 巡课系统是一种新的课堂观察记录工具,它将学校或区域内全体教师作为一个整体,采用数字化手段描述教师和学生的课堂行为。通过移动端实时记录和通用性的统计分析,使教育者更容易发现教学过程与教学成果之间的联系,有助于改变课堂生态、提高教学有效性、提升教…

Codeforces Round 895 (Div. 3)补题

Two Vessels(Problem - A - Codeforces) 题目大意:有两个无限容器,目前一个容器中有a克水,另一个容器中有b克水,现有一个大小为cg的容器,我们每次可以从一个无限容器中取任意不大于c克的水&…

【Linux】相关背景及环境搭建

前言: 认识 Linux, 了解 Linux 的相关背景,学会如何使用云服务器,掌握使用远程终端工具 xshell 登陆 Linux 服务器 文章目录 一、Linux介绍1.1 关于UNIX1.2 Linux的诞生及发展历程1.3 Linux开源1.4 Linux在各个行业的现状1.5 发行版本 二、Li…

令牌桶算法与Guava的实现RateLimiter源码分析

令牌桶算法与Guava的实现RateLimiter源码分析 令牌桶RateLimiter简介RateLimiter使用示例导入maven依赖编写测试代码 RateLimiter的实现源码解析SmoothRateLimiterSmoothBursty恒速获取令牌acquire(int)tryAcquire(int,long,TimeUnit) 存量桶系数小结 优缺点与漏桶的区别总结 令…

Python爬虫时被封IP,该怎么解决?四大动态IP平台测评

在使用 Python 进行爬虫时,很有可能因为一些异常行为被封 IP,这主要是因为一些爬虫时产生的异常行为导致的。 在曾经的一次数据爬取的时候,我尝试去爬取Google地图上面的商家联系方式和地址信息做营销,可是很不幸,还只…

CloudPanel file-manager/backend/makefile接口存在远程命令执行漏洞CVE-2023-35885

@[toc] 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. CloudPanel 简介 微信公众号搜索:南风漏…

【漏洞复现】Hikvision摄像头产品越权漏洞(CVE-2017-7921)

Nx01 产品简介 Hikvision(海康威视)是一家在中国颇具影响力的安防公司,其网络摄像头产品在市场上占据了相当大的份额。Hikvision的网络摄像头产品线非常丰富,涵盖了各种型号和功能,以满足不同用户的需求。 Nx02 漏洞描…

Spring DI

目录 什么是依赖注入 属性注入 构造函数注入 Setter 注入 依赖注入的优势 什么是依赖注入 依赖注入是一种设计模式,它通过外部实体(通常是容器)来注入一个对象的依赖关系,而不是在对象内部创建这些依赖关系。这种方式使得对象…

03-黑马程序员大数据开发:Apache Hive

一、 Apache Hive概述 1. 目的:了解什么是分布式SQL计算;了解什么是Apache Hive 2. 使用Hive处理数据的好处 操作接口采用类SQL语法,提供快速开发的能力(简单、容易上手)底层执行MapReduc…

第七回 林教头刺配沧州道 鲁智深大闹野猪林-FreeBSD/Linux图形界面安装配置

高俅定林冲:手持利刃,故入节堂,杀害本官的罪名,将林冲押解去开封府,暗示开封府将林冲处决。 开封府负责办案的叫孙定,他为人刚正不阿,宅心仁厚。在他的据理力争之下,开封府尹最终对…

【linux】ps的基本使用

ps是linux中用于显示进程的工具,确切来说是显示活动进程的工具 ps的基本格式是 ps [选项] sh-3.2# ps --help ps: illegal option -- - usage: ps [-AaCcEefhjlMmrSTvwXx] [-O fmt | -o fmt] [-G gid[,gid...]][-g grp[,grp...]] [-u [uid,uid...]][-p pid[,pid..…

windows下redis使用教程

创建临时服务 redis-server.exe redis.windows.conf启动客户端 验证 # 使用set和get命令,对Redis数据库进行数据存储和获取,如下图所示 config get *创建永久服务 关闭临时服务的cmd窗口,输入以下命令 redis-server.exe --service-insta…