测试开发面试题---JVM

JAVA的内存区域

  • 程序计数器:线程私有的,保存当前线程的字节码文件。
  • JAVA虚拟机栈:包含局部变量信息,用于方法的调用和执行。
  • 本地方法栈:与JAVA虚拟机栈类似,但只服务于本地方法。
  • 堆:所有线程共享,存放对象实例变量,GC的主要区域。
  • 方法区:所有线程共享,用于存放已经被JVM加载的类信息。
  • 运行时常量池:所有线程共享,方法区的一部分,存储编译期间生成的字面量和符号引用

JAVA栈和堆的区别

  • 栈主要用于存储局部变量和方法调用的上下文信息,栈中数据生命周期短暂,当元素调用结束时,占空间会被释放;每个线程有自己独立的栈空间,栈上的数据不能被其他线程访问和修改;堆栈上的数据访问速度更快(堆中数据涉及复杂的算法保证数据分配和回收)。
  • 堆主要用于存储对象实例和变量,堆的生命周期不稳定,当对象不再被引用时,堆会自动调用GC进行回收,堆中的数据所有线程共享,可以被其他线程访问和修改。 

JAVA虚拟机栈溢出情况

  • 递归调用过深:当一个方法调用自身时,如果没有正确的终止条件或者终止条件不满足。
  • 方法调用层次过深:层层嵌套调用。
  • 线程过多
  • 栈帧过大:方法中局部变量过多,或者单个局部变量过大
  • JVM参数配置不当:JVM为每个线程分配的栈过小。

解决方法

  • 优化递归逻辑,确保递归调用有明确的终止条件,如果可以,将递归改为迭代。
  • 合理设置JVM参数,增加每个线程的大小。
  • 避免无限制创建线程。

垃圾回收(GC)算法

  • Serial:单线程,在回收垃圾的时候会暂停所有的事情。
  • CMS:多线程,采用标记-清理方法产生大量空间碎片。
  • G1:多线程,强化分区,将JVM堆划分为多个区域,每次选择最多的区域进行回收。

类加载器

类加载器是JVM加载类文件的组件,它负责将字节码文件加载到内存中并转化为.class对象。

类加载过程

  1. 加载:根据类的全限定名查找它的字节码文件并创建.class对象
  2. 验证:验证类文件格式是否正确
  3. 准备:为静态变量创建内存并初始化默认值
  4. 解析:将符号引用改为直接引用
  5. 初始化:之形类的静态初始化块以及对静态变量赋值

分类

启动类加载器、扩展类加载器和应用程序类加载器

双亲委派模型

当一个类加载器需要加载一个类的时候,它先让它的父类去加载这个类,如果父类无法加载它就自己加载,这主要是为了避免核心类库被重复加载。

进程和线程

  • 进程:资源分配的基本单位,拥有独立的内存空间和资源,创建和销毁开销大,具有良好的错误隔离和稳定性。
  • 线程:程序执行的基本单位,共享进程的内存资源,适合高效的并发和并行程序。
  • 并发:一个系统能够处理多个任务,这些任务不需要同时执行
  • 并行:同一时刻执行多个任务

用户线程:执行具体的业务逻辑,完成程序的核心功能。只要有一个用户线程在执行,JVM就不会退出。

守护线程:提供辅助功能,主要用于后台任务,它的生命周期取决于用户线程,一旦用户线程执行完毕,JVM会强制退出,所有的守护线程也会退出。

Start和Run方法

Start会创建并执行一个新的线程,Run只是执行当前线程不会启动一个新线程。

线程状态

  1. new:线程刚创建时候
  2. 就绪:在可运行线程池中等待CPU时间片
  3. 运行:获得CPU时间片开始运行
  4. 阻塞:等待某种条件的发生(等待锁的释放)
  5. 终止:线程执行完毕

Sleep和Wait

  • Sleep是线程类的方法,它不会释放锁而是在指定时间后恢复对线程的执行;用于定时任务或者防止循环过快消耗CPU资源。
  • Wait是Object类的方法,它会释放锁然后等待另一个线程用notify来唤醒;用于线程间的同步和通信。

公平锁:保证线程按照它们申请的顺序获得锁,每个线程都会获得锁不会导致线程饥饿。

非公平锁:不保证线程按照它们申请的顺序获得锁,锁的获取和释放更快,但可能导致线程饥饿。

Sychronized锁

JAVA的关键字,用于线程之间互斥和同步,作用于方法和代码块;由JVM管理,简单易用,可重入,自动释放锁;它是自动释放锁,可能会导致线程饥饿,不可中断。保证互斥、原子性和可见性。

Sychronized锁升级

  • 偏向锁:优化技术,减少无竞争情况下的同步代价。如果一个线程获得了偏向锁,它在接下来的的锁请求中无需进行同步操作,直接进入临界区。只有在其他线程尝试竞争这把锁的时候,偏向锁才会撤销(锁的头部会记录第一个获得锁线程的ID,当这个锁再次被线程请求的时候,无需CAS直接进入临界区)。适合于无竞争情况,减少无竞争下的同步开销。
  • 轻量级锁:自旋锁,线程获取锁失败的时候不立即阻塞而是忙循环反复尝试获取锁。适合于竞争时间比较小的锁,避免线程阻塞和唤醒的开销。
  • 锁粗化:将多个小范围锁合并成一个大范围的锁,减少加锁解锁的开销。
  • 锁去除:在编译期间判断锁对象是否只在当前线程内使用,如果是则去除锁。

首先,Sychronized通过尝试获取偏向锁来竞争资源,如果能竞争到代表加锁成功,如果不行则需要将锁升级为轻量级锁,在轻量级锁状态下线程会根据自旋次数来抢占锁资源,如果还是无法竞争到,会升级到重量级锁,在重量级锁状态下,没有竞争到锁的线程会被阻塞。

Volatile

轻量级的同步机制保证变量的可见性和有序性,它通过将修改后的值直接刷新到内存中来确保其他线程对修改后的变量值立即可见;通过禁止指令重排序来达到有序性。

Lock

Lock最常用的实现类是Reentrantlock(可重入锁,允许一个线程多次获取同一个锁而不会阻塞)。它的锁的获取和释放需要显示调用lock()和unlock()方法,它可以被配置为公平锁或者非公平锁;提供了trylock()方法来中断锁,提供了更加强大的功能,是用于处理复杂场景。

Sychronized与Volatile区别

Volatile比Sychronized有更小的性能开销,但Volatile只保证可见性和有序性,不保证复杂操作的原子性,它只适合状态标志、配置参数等不涉及复杂逻辑的变量,在复杂场景下仍旧使用Sychronized。

Sychronized与Lock区别

Sychronized是JAVA关键字,Lock是JUC的接口;Lock的灵活性更高,它可以使用lock()和unlock()方法随时加锁、解锁,Sychronized只能在同步代码块执行完自动释放锁;Lock提供了非公平锁和公平锁,Sychronized只提供非公平锁;如果同步代码块中抛出异常,Sychronized会自动释放,Lock则需要在finally中显示释放,否则会导致死锁。总之,Sychronized提供了更加简单直接的同步机制,而Lock提供了功能更加强大更灵活的同步机制。

Threadlock

Threadlock是线程变量,为每个使用该变量的线程提供了一个变量副本,每个线程可以独立修改自己的变量副本而不受其他线程的影响。它的实现核心在于每个线程维护了一个ThreadlockMap的对象,该对象保存了自己的本地变量。

使用场景

  • 线程的上下文切换
  • 数据库连接
  • 事务管理,事务处理中保存每个事务信息
  • 对象跨层传递时,打破层级间的约束避免多次传递

可能会导致内存泄漏,因为ThreadlockMap键是弱引用,但是它的值是强引用。当Threadlock没有被其他引用时,它会被GC收回,但是它的值无法回收。每次使用Threadlock后要利用remove清除数据。

JAVA内存模型

  • 可见性:线程对变量的修改对其他线程可见
  • 原子性:操作是不可以分割的,要么完全成功要么失败
  • 有序性:禁止指令重排序
  • 工作内存和主内存:主内存是线程共享区域,工作内存是每个线程私有区域。工作内存中保留了线程所需要的变量副本,线程修改变量的时候是在工作内存中,修改完成后刷新到主内存中。

JAVA内存模型中的关键机制

  • Volatile:可见性和有序性
  • Sychroized:互斥、可见性、有序性和原子性
  • happens-before:保证前一个操作在后一个操作之前且对后一个操作可见。

JAVA中常见的并发容器

  • ConcurrentHashMap:采用分段锁的技术,将整个数据分为多个段,每个段使用独立锁,在JAVA 8以后,采用更加高效CAS和同步链表代替分段锁,进一步提高性能。
  • CopyonWriteArraylist:写操作时,不直接修改原来的数组而是创建一个新的数组,使用新数组来代替就数组,在读多写少的情况下性能更高。

线程池

线程启动前就创建若干个线程等待响应,减少了频繁创建和销毁线程的开销,通过控制并发线程数量和合理的任务调度来更好地进行资源调度;避免在高并发下因为创建过多线程导致系统崩溃,提供了更好的系统稳定性;在完成任务后将线程归还到池中,避免线程未正确销毁导致的泄露。

线程池的参数

  • 核心线程数:线程池中始终保持的线程数量,线程池会优先使用核心线程来执行任务
  • 最大线程数:线程池中可以创建线程的上限
  • 空闲线程存活时间:非核心线程在执行完任务后最久存活时间
  • 任务队列:存储等待执行的线程,当前线程数达到核心线程的数量时,新提交的任务会保留在任务队列中
  • 拒绝策略:当任务队列已满且达到最大线程数时,线程池无法接受新的任务

实现原理

线程池在创建时根据默认的参数配置核心线程,无论是否当前有任务需要执行,这些线程都会一直保留在线程池中。当需要执行任务时,线程池会优先使用这些线程去执行。如果当前没有空闲的核心线程,就会把这个任务放在任务队列中等待执行。如果任务队列已满但还未达到线程池中所能接受的最大核心数时,线程池会创建一个新的线程去处理这个任务。当任务队列已满且线程数达到最大线程数时,线程池采用拒绝策略停止继续工作。任务完成后,线程会返回空闲状态。核心线程不会回收,非核心线程会根据空闲线程存活时间进行回收。当线程池不在需要的时候,调用shutdown()和shutdownnow()来执行(shutdown()是等待已提交的任务完成后回收,shutdownnow()会尝试停止当前正在执行的任务然后回收)

线程池的拒绝策略

  • 默认策略:直接抛出异常
  • 调用者运行策略:提交任务的线程自己处理任务,降低任务提交速度
  • 直接丢弃策略:丢弃无法处理的任务,不抛出异常
  • 丢弃最旧策略:丢弃队列中最旧的未处理的任务

execute和submit区别

execute只能提交实现了Runnable接口的任务,不返回任何结果,当出现异常时会直接抛出异常。submit可以提交实现了Runnable和Callable接口的任务,对于Callable任务会返回一个Future对象,这个对象可以检查任务是否完成,如果遇到异常允许调用者捕获并处理异常。

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

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

相关文章

VMWare 16 安装

1、下载地址 VMware-workstation-full-16.2.4-20089737 2、激活码 VM16:ZF3R0-FHED2-M80TY-8QYGC-NPKYF 3、安装步骤 修改一下【安装位置】,将【增强型键盘驱动程序(需要重新引导以使用此功能()此功能要求主机驱动器上具有 10MB 空间。】【将 wMware…

使用ChatGPT来撰写和润色学术论文的教程(含最新升级开通ChatGpt4教程)​​

现在有了ChatGPT4o更加方便了, 但次数太少了 想要增加次数可以考虑升级开桶ChatGpt4​​ ( OPENAI4 可以减2刀) 一、引言 在学术研究中,撰写高质量的论文是一项重要的技能。本教程将介绍如何利用ChatGPT来辅助完成从论文构思到润色的全过程…

Hadoop 重要监控指标

某安卓逆向课程打包下载(92节课) ​​https://pan.quark.cn/s/53cec8b8055a ​​ 某PC逆向课程(100节课打包下载) ​​https://pan.quark.cn/s/e38f2b24f36c​​ Hadoop 是一个开源的分布式存储和计算框架,广泛应用…

JUC-synchorized与锁原理、锁的升级与膨胀

syn-ed 是一个可重入、不公平的重量级锁;synchronized使用对象锁保证了临界区代码的原子性,无论使用synchorized锁的是代码块还是方法,其本质都是锁住一个对象。 同步代码块,锁住的是括号里的对象同步方法 普通方法,…

Adobe“加速”创意人士开启设计新篇章

近日,Adobe公司宣布了其行业领先的专业设计应用程序——Adobe Illustrator和Adobe Photoshop的突破性创新。这一重大更新不仅为创意专业人士带来了前所未有的设计可能性和工作效率提升,还让不论是插画师、设计师还是摄影师,都能从中受益并创作…

GO内存分配详解

文章目录 GO内存分配详解一. 物理内存(Physical Memory)和虚拟内存(Virtual Memory)二. 内存分配器三. TCMalloc线程内存(thread memory)页堆(page heap)四. Go内存分配器mspanmcachemcentralmheap五. 对象分配流程六. Go虚拟内存ArenaGO内存分配详解 这篇文章中我将抽丝剥茧,…

Redisson中RQueue的使用场景附一个异步的例子

RQueue 是一个基于 Redis 的分布式作业队列系统,它允许开发者在 Ruby 应用程序中实现异步任务处理和计划任务调度。由于 Redis 提供了高性能的内存数据结构存储,RQueue 可以快速地存储和检索队列中的任务,这使得它非常适合于高并发和低延迟的…

【Langchain大语言模型开发教程】评估

🔗 LangChain for LLM Application Development - DeepLearning.AI 学习目标 1、Example generation 2、Manual evaluation and debug 3、LLM-assisted evaluation 4、LangChain evaluation platform 1、引包、加载环境变量; import osfrom dotenv imp…

UVM-config_db机制和用法

1.用途 config_db机制用于在UVM验证平台间传递参数,通常成对出现,其中set相当于寄信,get相当于收信。UVM提供的config_db机制可在组件实例化前就设定好配置信息,这样就可在tb的initial块中就进行设定了。真正将这些配置信息落实在…

RK3568 Linux 平台开发系列讲解(内核入门篇):如何高效地阅读 Linux 内核设备驱动

在嵌入式 Linux 开发中,设备驱动是实现操作系统与硬件之间交互的关键。对于 RK3568 这样的平台,理解和阅读 Linux 内核中的设备驱动程序至关重要。 1. 理解内核架构 在阅读设备驱动之前,首先要了解 Linux 内核的基本架构。内核主要由以下几个部分组成: 内核核心:处理系…

【word转pdf】【最新版本jar】Java使用aspose-words实现word文档转pdf

【aspose-words-22.12-jdk17.jar】word文档转pdf 前置工作1、下载依赖2、安装依赖到本地仓库 项目1、配置pom.xml2、配置许可码文件(不配置会有水印)3、工具类4、效果 踩坑1、pdf乱码2、word中带有图片转换 前置工作 1、下载依赖 通过百度网盘分享的文…

Golang实现免费天气预报获取(OpenWeatherMap)

最近接到公司的一个小需求,需要天气数据,所以就做了一个小接口,供前端调用 这些数据包括六个元素,如降水、风、大气压力、云量和温度。有了这些,你可以分析趋势,知道明天的数据来预测天气。 1.1 工具简介 …

《Java8函数式编程》学习笔记汇总

前言 见证了java8的多层排序,为此想系统学习下java8的用法。 目录 简介Lambda表达式流高级集合类和收集器数据并行化测试、调试和重构设计和架构的原则使用Lambda表达式编写并发程序下一步改怎么办 后记

tinyxml2的入门教程

tinyxml2的入门教程 前言一、tinyxml2 创建xml 文件二、tinyxml2 添加数据三、tinyxml2 更改数据四、tinyxml2 删除数据五、tinyxml2 打印总结 前言 xml 是一种标记型文档,有两种基本解析方式:DOM(Document Object Model,文档对象模型)和SAX…

尚品汇-sku存入Redis缓存(二十三)

目录: (1)分布式锁改造获取sku信息 (2)使用Redisson 分布式锁 AOP实现缓存 (3)定义缓存aop注解 (1)分布式锁改造获取sku信息 前面学习了本地锁的弊端,…

NFTScan 浏览器现已支持 .mint 域名搜索功能!

近日,NFT 数据基础设施 NFTScan 浏览器现已支持用户输入 .mint 域名进行 Mint Blockchain 网络钱包地址的搜索查询, NFTScan 用户能够轻松地使用域名追踪 NFT 交易,为 NFT 钱包地址相关的搜索查询功能增加透明度和便利性。 NFTScan explorer…

MATLAB算法实战应用案例精讲-【数模应用】Poisson 回归分析(附R语言、python和MATLAB代码实现)

目录 前言 知识储备 常见回归方法 一、 回归分析方法概述 二、 分类 1.应用领域分类 (1)通用型 (2)统计学角度 (3)计量角度 (4)社科学角度 (5)医学角度 (6)数学建模 (7)专业型 Poisson回归和负二项回归 1.前提条件 2.分析流程图 3.案例分析 算…

通讯规约协议

通讯规约协议(Communication Protocol),又称为通信规程,是随着现代通信技术和计算机网络技术的发展而发展的规约。它是通信双方对数据传送控制的一种约定,包括对数据格式、同步方式、传送速度、传送步骤、检纠错方式以…

Java8-求两个集合取交集

在Java8中,求两个集合的交集可以使用不同的三种方式:传统的循环遍历、使用Stream API的filter操作和使用Stream API的Collection操作。 方法一:传统的循环遍历 首先,我们创建两个集合list1和list2,并给它们添加一些元…

vue + xterm 前端终端terminal

引入 import {Terminal} from "xterm"; import {FitAddon} from "xterm-addon-fit"; import "xterm/css/xterm.css";html <div id"terminal"></div>vue onMounted(() > {nextTick(() > {initTerm();}) })const i…