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

Java100道面试题

1.JVM内存结构

VM内存结构指的是JVM运行时数据区结构,它主要包含以下几个部分:

堆(Heap):线程共享。

JVM堆(Heap)是Java虚拟机中的一块内存区域(所有线程共享),主要用于存储对象实例和数组。堆被划分为三个部分:年轻代、老年代和永久代(在JDK8中取消了永久代),其中,年轻代又被划分为Eden区、Survivor区(含:S0和S1)

方法区(Method Area):线程共享。

在JDK8及之前,方法区属于永久代,而在JDK8之后,永久代被移除,方法区被移到了本地内存中,即:元空间(Meta Space)。

元空间逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫非堆。元空间是各个线程共享的内存区域,它主要存储两部分内容:

虚拟机栈(VM Stack):线程私有。

虚拟机栈为线程私有,它描述的是Java方法执行的内存模型。每个栈由多个栈帧(Stack Frame)组成,每个方法被执行时,Java虚拟机都会同步创建一个栈帧用于存储该方法的局部变量表、操作数栈、动态链接、方法返回地址等信息

程序计数器(Program Counter Register):线程私有

  • 每个线程都有一个独立的程序计数器,各线程之间计数器互不影响,独立存储。

  • 执行Java方法时,程序计数器的值不为空;执行Native本地方法时,程序计数器的值为空(Undefined)。

  • 程序计数器是唯一一个在Java虚拟机规范中没有规定任何内存溢出情况的区域

本地方法栈(Native Method Stack):线程私有

本地方法栈与虚拟机栈类似,不同的是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务。在Java程序调用Native方法时,Native方法所需要的内存空间在本地方法栈中开辟。

2.垃圾回收机制(GC)

JVM的垃圾回收机制:GC,是Java提供的对于内存自动回收的机制。

GC(Garbage Collection)是Java虚拟机(JVM)中的一项重要功能,用于自动管理堆内存中不再使用的对象,释放其占用的内存空间。GC通过标记和回收无效对象来实现内存的回收和释放,以避免内存泄漏和溢出。

        下面是GC的主要工作原理和过程:

        1、对象的标记:GC首先标记出所有活动对象,即仍然被引用或可达的对象。它从一组根对象开始,逐步遍历对象图,将可达的对象标记为活动对象,未标记的对象则被认为是无效的。

        2、垃圾回收:在标记完成后,GC会对未标记的对象进行回收。具体的回收算法可以是不同的,常见的算法包括标记-复制算法、三色标记算法等。

        3、内存压缩和整理:某些垃圾回收算法在回收完对象后,可能会产生内存碎片。为了优化内存使用,GC可能会进行内存压缩和整理操作,使得分配的对象在内存中连续存放,减少内存碎片的影响。

        GC的优点是可以自动管理内存,减少了手动内存管理的复杂性,避免了内存泄漏和溢出的问题。但是,GC也会带来一定的性能开销。因此,在开发Java应用程序时,需要合理配置GC的参数和调整垃圾回收策略,以平衡性能和内存的使用。
 

3.JVM调优的方法?

1. 明确优化目标

在开始调优之前,首先需要明确优化的目标。这包括响应时间、吞吐量、内存使用率等指标。明确目标后,可以更有针对性地进行调优

2. 监控和分析
  1. 使用监控工具:利用Java VisualVM、JConsole、JProfiler等监控工具,分析CPU使用率、内存使用情况和垃圾回收频率等指标。
  2. 分析GC日志:通过GC日志,了解垃圾回收的频率、停顿时间以及内存使用情况,帮助定位性能瓶颈。

3. 确定调优参数

根据监控和分析的结果,确定需要调整的JVM参数。常见的JVM参数包括:

  1. 堆内存设置:通过-Xms和-Xmx设置初始和最大堆内存大小。
  2. 垃圾收集器选择:选择合适的垃圾收集器,如G1、CMS等,以优化内存管理
  3. 线程栈大小:通过-Xss设置每个线程的堆栈大小,以减少线程上下文切换的开销。

4. 实施调优策略

  1. 调整JVM参数:根据确定的调优参数,调整JVM的启动参数。
  2. 优化代码:减少不必要的对象创建、使用高效的数据结构、避免过度的同步等,都可以显著提升应用的性能。

5. 持续观察和调整

  1. 持续监控:在调整参数和优化代码后,使用监控工具持续观察应用的性能变化。
  2. 对比性能指标:通过对比调优前后的性能指标,确认是否达到了预期的优化目标。
  3. 重新评估和调整:如果没有达到目标,可能需要重新评估调优策略,进行进一步的调整。

6. 定期评估和优化

性能调优是一个持续的过程。随着应用的演变和用户负载的变化,可能需要定期重新评估和调整JVM参数。定期的性能测试和监控可以帮助及时发现潜在问题,确保系统的稳定性和高效性。

4.堆和栈的区别?

Java堆和栈是Java虚拟机(JVM)中的两个重要概念,它们在内存管理、存储对象和执行线程等方面有明显的区别。

1、内存分配和管理
Java堆是动态分配的内存区域,主要用来存储对象实例。在Java中,对象是通过堆内存进行分配的。当创建一个对象时,Java虚拟机会在堆上分配相应的内存空间,并自动进行垃圾回收和内存管理。堆的大小可以在运行时动态调整,通过JVM参数进行配置。
相比之下,Java栈是线程私有的,每个线程在创建时都会创建一个栈。栈由一系列栈帧组成,每个栈帧对应一个方法调用。栈主要用于存储基本数据类型、对象引用和方法的局部变量。每个方法从调用开始到执行结束的过程,对应一个栈帧在栈内存中的入栈到出栈的过程。

2、存储内容
Java堆主要用于存储对象实例,它是所有线程共享的一块内存区域。堆中可以存储任意类型的对象,包括数组和类的实例。堆中的对象可以是任意的Java对象,如String、Integer等。堆是由垃圾回收器自动管理的,当一个对象不再被引用时,垃圾回收器会自动回收该对象占用的堆内存。
Java栈主要存储基本数据类型、对象引用和方法的局部变量。每个方法从调用开始到执行结束的过程,对应一个栈帧在栈内存中的入栈到出栈的过程。每个方法从调用直至执行完成的过程,对应着一个栈帧在虚拟机栈中入栈到出栈的过程。栈帧是用于支持虚拟机进行方法执行的数据结构,也是虚拟机运行时数据区中的一块内存区域。

3、线程执行和生命周期
Java堆是所有线程共享的内存区域,而Java栈是线程私有的。每个线程在创建时都会创建一个自己的栈,并且这个栈的生命周期与线程相同。当线程启动时,它的栈随之创建;当线程结束时,它的栈也随之销毁。每个方法的执行都伴随着一个栈帧的入栈和出栈过程,方法的执行过程对应着其栈帧在栈内存中的生命周期。
相比之下,堆的生命周期与应用程序的启动和结束相同。当应用程序启动时,堆被创建;当应用程序结束时,堆随之销毁。垃圾回收器自动管理堆内存的回收和释放。

4、性能影响
由于Java堆是所有线程共享的内存区域,因此对堆的操作是共享的。这意味着多个线程可以同时访问堆中的数据,并进行读写操作。这种共享性使得堆在某些情况下可以提高多线程程序的性能。
相比之下,Java栈是线程私有的,每个线程都有自己的独立栈。因此,对栈的操作是线程独占的。这意味着同一时间只有一个线程可以访问某个栈帧中的数据,这有助于避免多线程并发访问带来的问题。但是,由于每个线程都有自己的独立栈,因此可能会占用更多的内存空间

5.JVM使用命令

jvm 的一些命令_jvm命令-CSDN博客

6.class.forName和Classload的区别

1.相同点
两者都可以对类进行加载。
对于任意一个类/对象,我们都能够通过反射能够调用这个类的所有属性方法。

2.不同点
抽象类ClassLoader中实现的方法loadClass,loadClass只是加载,不会解析更不会初始化所反射的类。常用于做懒加载,提高加载速度,使用的时候再通过.newInstance()真正去初始化类。 

7.谈谈JDK1.8特性有哪些

Lambda表达式 类似于ES6中的箭头函数
接口的默认方法和静态方法
新增方法引用格式
新增Stream类
新的日期API,Datetime,更方便对日期的操作
引入Optional,在SpringData中使用较多,然后再通过get获取值,主要用于防止NPE。
支持Base64
注解相关的改变
支持并行(parallel)数组
对并发类(Concurrency)的扩展。
JavaFX。

JDK1.8常用新特性_jdk1.8的新特性-CSDN博客

8.反射获取类中的所有方法和获取类中的所有属性

9.懒汉和饿汉模式的区别?口述两种模式。 

在饿汉式单例模式中,“饿” 体现的是一种急切的状态。就好像一个很饿的人,在看到食物(这里类比于单例对象)的时候,会迫不及待地先把食物拿到手(创建单例对象)。在这个模式下,单例对象在类加载阶段就被创建出来,而不是等到真正需要使用这个对象的时候才去创建。这种方式比较急切,所以被称为 “饿汉模式”。

在懒汉模式下,实例在第一次使用时才进行创建,因此称为“懒汉”,在需要被用的时候被创建,突出一个字“懒”

10.如何保证单例模式在多线程中的线程安全

私有构造函数:通过将构造函数设置为私有,我们禁止了外部类直接实例化Singleton类。这确保了只能通过getInstance()方法来获取实例。

volatile关键字:volatile关键字确保了instance变量的可见性。当一个线程修改了一个volatile变量的值时,其他线程能够立即看到这个变化。这样可以避免线程之间的缓存不一致问题。

双重检查锁定(Double-Checked Locking):为了减少同步开销,我们在第一次检查instance是否为空后,才进入同步块。这是因为大多数情况下,实例已经被创建,不需要进入同步块。只有在第一次创建实例时才会需要同步。

同步块:在同步块内部,我们再次检查instance是否为空,以确保只有一个线程能够创建实例。这是为了防止多个线程同时通过了第一个空检查并尝试创建多个实例。


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

相关文章:

  • Vue3+Element Plus的表格分页实战
  • 力扣--34.在排序数组中查找元素的第一个和最后一个位置
  • 【Rust自学】10.6. 生命周期 Pt.2:生命周期的语法与例子
  • 机器人对物体重定向操作的发展简述
  • 在Linux中,如何查看和修改网络接口配置?
  • 卡码网 ACM答题编程模板
  • GaussDB逻辑解码技术原理深度解析
  • 使用JMeter玩转tidb压测
  • df.replace(regex={‘b‘: {r‘\s*\.\s*‘: np.nan}})
  • Java项目实战II基于小程序的驾校管理系统(开发文档+数据库+源码)
  • 如何判断状态:停留还是移动。【计算加速度de方案】
  • 计算机网络——数据链路层-功能、组帧和差错控制
  • 博客标题:使用Go和RabbitMQ构建高效的消息队列系统
  • IEEE PDF eXpress遇到Font TimesNewRomanPSMT is not embedded的解决方案
  • Android 性能优化:内存优化(实践篇)
  • 以太网ICMP协议(ping指令)——FPGA学习笔记25
  • 文献阅读 | B. S. Carmo 2010
  • springcloud篇3-docker需熟练掌握的知识点
  • leetcode hot 100 分割等和子集
  • 自动化立体仓库堆垛机SRM控制系统主系统控制功能块开发
  • 传统测量VS三维扫描
  • SquareLine Studio教程 图形化 LVGL 移植实际硬件 RP2040
  • cmd指令查看关闭端口进程
  • T-SQL语言的正则表达式
  • idea java.lang.OutOfMemoryError: GC overhead limit exceeded
  • 《learn_the_architecture_-_aarch64_exception_model》学习笔记