当前位置: 首页 > article >正文

JVM面试真题总结(九)

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

在这里插入图片描述

描述CMS垃圾收集的工作过程

CMS(Concurrent Mark Sweep)垃圾收集器的工作过程

主要可以分为以下四个阶段:

初始标记(Initial Mark)

  • 这个阶段的目标是标记所有的 GC Roots 能直接关联到的对象。
  • 这个阶段需要停止所有的用户线程,但是一般情况下,这个阶段会很快完成。

并发标记(Concurrent Mark)

  • 在这个阶段,垃圾收集器会遍历对象图,并标记所有的存活对象,从初始标记的对象开始。
  • 这个阶段是与用户线程并发执行的,不需要停止用户线程。

重新标记(Remark)

  • 因为在并发标记阶段,用户线程还在运行,可能会修改了对象图,所以需要重新标记一次,以确保标记的准确性。
  • 这个阶段需要停止所有的用户线程。

并发清除(Concurrent Sweep)

  • 在这个阶段,垃圾收集器会清除所有未被标记的对象。
  • 这个阶段是与用户线程并发执行的,不需要停止用户线程。

如何防止内存泄漏?

防止内存泄漏主要需要对代码进行精细的管理和控制,以下是一些常用的方法:

及时释放对象:

  • 当对象不再使用时,及时将其引用设置为null,以便让垃圾回收器能够回收。

使用弱引用(WeakReference):

  • 在Java中,使用WeakReference可以在不影响垃圾回收器回收对象的同时,还能使用到这个对象。
  • 当该对象只剩下弱引用时,垃圾回收器会回收它。

避免使用静态变量:

  • 静态变量会在类加载时初始化,并在整个程序运行期间都存在,容易造成内存泄漏。
  • 如果非要使用,应确保在不需要时将其设置为null

及时关闭流、数据库连接等资源:

  • 这些资源都是有限的,使用完后必须及时关闭,否则会造成资源泄漏。

使用finally块:

  • 在Java中,finally块始终会被执行,无论是否有异常发生。
  • 因此,可以在finally块中释放资源。

避免在对象中保存过多的数据:

  • 如果一个对象保存了大量的数据,那么当这个对象被其他对象引用时,会消耗大量的内存。

使用内存分析工具:

  • 内存分析工具(如MAT,VisualVM等)可以帮助你找出内存泄漏的来源,从而更好地修复问题。

对集合类进行适当的管理:

  • 对于集合类,如List,Map等,应该避免让它们过大,并且在不再使用它们时,应该清空或者设置为null

注意线程的使用:

  • 如果线程对象得不到及时的销毁,也会造成内存泄漏。
  • 因此,对于线程对象,我们要特别小心,确保其生命周期得到良好的管理。

简述内存屏障及其类型

内存屏障(Memory Barrier),也被称为内存栅栏,是一种处理器指令

  • 用于防止特定操作的重排序。

它可以确保某些内存操作的顺序性,以及它们对其他处理器可见的顺序。

内存屏障是处理器设计和多线程编程中的重要概念

  • 它是实现诸如volatile,synchronized等高级同步构造的基础。

内存屏障主要有以下四种类型:

LoadLoad屏障:

  • 这种屏障确保了屏障之前的所有Load操作在屏障之后的Load操作之前完成。
    • 即不允许Load操作的重排序。

StoreStore屏障:

  • 这种屏障确保了屏障之前的所有Store操作在屏障之后的Store操作之前完成。
    • 即不允许Store操作的重排序。

LoadStore屏障:

  • 这种屏障确保了屏障之前的所有Load操作在屏障之后的Store操作之前完成。

StoreLoad屏障:

  • 这种屏障确保了屏障之前的所有Store操作在屏障之后的Load操作之前完成。
  • 这是最强的一种内存屏障,也是开销最大的一种。

在Java中,volatile关键字和synchronized关键字的实现就使用了内存屏障。

例如,对volatile变量的写操作会插入StoreStore和StoreLoad屏障

  • 读操作会插入LoadLoad和LoadStore屏障。

而synchronized关键字在锁定和解锁时也会插入相应的内存屏障,以确保操作的顺序性和可见性。

哪些情况会导致栈内存溢出?

栈内存溢出一般发生在递归调用且递归深度过深的场景。

  • 当一个线程请求的栈深度大于JVM所允许的深度,将抛出StackOverflowError异常。

栈内存主要用于存储局部变量和执行动态链接,还用于方法调用和返回。

  • 每次方法调用都会创建一个新的栈帧,这个栈帧会被添加到线程的栈顶。
  • 如果这个方法调用其他方法,那么新的栈帧会继续被添加到栈顶。
    • 当方法调用完成,相应的栈帧会被弹出栈。

每个线程都有一个私有的JVM栈,其大小可以固定也可以动态扩展。

  • 如果固定大小的栈满了,或者动态扩展的栈无法继续扩展,那么JVM就会抛出StackOverflowError

例如,如果你写了一个递归函数,没有提供适当的递归出口,那么这个函数就会无限递归下去

  • 每次递归都会向栈添加一个新的栈帧,最终导致栈内存溢出。
public void recursive() {
    recursive();
}

以上面的代码为例,这个方法会不断地调用自己,每次调用都会创建一个新的栈帧并压入栈中

  • 但是没有任何方法可以弹出栈帧,因此最终会导致栈内存溢出。

http://www.kler.cn/a/305160.html

相关文章:

  • Java学习--网络编程
  • 2024 kali操作系统安装Docker步骤
  • 【Linux】进程池实现指南:掌控并发编程的核心
  • Typescript类型运算符、关键字以及内置高级类型
  • Node.Js+Knex+MySQL增删改查的简单示例(Typescript)
  • 什么是两化融合
  • windows检查端口占用并关闭应用
  • git报错,error: bad signature 0x00000000fatal: index file corrupt
  • 3. 进阶指南:自定义 Prompt 提升大模型解题能力
  • 新手教学系列——用Nginx将页面请求分发到不同后端模块
  • 足球大小球及亚盘数据分析与机器学习实战详解:从数据清洗到模型优化
  • vue项目中引入组件时出现的Module is not installed问题
  • 上图为是否色发
  • 15、Python如何获取文件的状态
  • ARM V2处理器微架构分析
  • input和editor一起使用在ios上聚焦异常
  • 【计算机网络 - 基础问题】每日 3 题(四)
  • 目标检测中的解耦和耦合、anchor-free和anchor-base
  • 分销系统后端技术文档
  • 大数据Flink(一百一十八):SQL水印操作(Watermark)
  • Linux基础---07文件传输(网络和Win文件)
  • 9 递归——50. Pow(x, n) ★★
  • linux 操作系统下的curl 命令介绍和使用案例
  • docker如何实现资源隔离
  • Tomcat 版本怎么选?JMeter 真实压测多版本 Tomcat 数据给你最直接的参考,快收藏备用吧!
  • Gateway学习笔记