写点什么

Java 面试题原理和底层,java 面试突击第二季

用户头像
Java高工P7
关注
发布于: 22 分钟前

Java 对象头包括:


Mark Word(标记字段): 用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等等。它是实现轻量级锁和偏向锁的关键


Klass Pointer(类型指针): 是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例


monitor: 可以把它理解为一个同步工具, 它通常被描述为一个对象。 是线程私有的数据结构


4. ConcurrentHashMap 的工作原理,底层原理(谈到多线程高并发大几率会问它)


5. JVM 调优(JVM 层层渐进问时大几率问)


查看堆空间大小分配(年轻代、年老代、持久代分配)


垃圾回收监控(长时间监控回收情况)


线程信息监控:系统线程数量


线程状态监控:各个线程都处在什么样的状态下


线程详细信息:查看线程内部运行情况,死锁检查


CPU 热点:检查系统哪些方法占用了大量 CPU 时间


内存热点:检查哪些对象在系统中数量最大


jvm 问题排查和调优:


jps 主要用来输出 JVM 中运行的进程状态信息。


jstat 命令可以用于持续观察虚拟机内存中各个分区的使用率以及 GC 的统计数据


jmap 可以用来查看堆内存的使用详情。


jstack 可以用来查看 Java 进程内的线程堆栈信息。 jstack 是个非常好用的工具,结合应用日志可以迅速定位到问题线程。


Java 性能分析工具


jdk 会自带 JMC(JavaMissionControl)工具。可以分析本地应用以及连接远程 ip 使用。提供了实时分析线程、内存,CPU、GC 等信息的可视化界面。


JVM 内存调优


对 JVM 内存的系统级的调优主要的目的是减少 GC 的频率和 Full GC 的次数。 过多的 GC 和 Full GC 是会占用很多的系统资源(主要是 CPU),影响系统的吞吐量。


使用 JDK 提供的内存查看工具,比如 JConsole 和 Java VisualVM。


导致 Full GC 一般由于以下几种情况:


旧生代空间不足


调优时尽量让对象在新生代 GC 时被回收、让对象在新生代多存活一段时间和不要创建过大的对象及数组避免直接在旧生代创建对象


新生代设置过小


一是新生代 GC 次数非常频繁,增大系统消耗;二是导致大对象直接进入旧生代,占据了旧生代剩余空间,诱发 Full GC


2). 新生代设置过大


一是新生代设置过大会导致旧生代过小(堆总量一定),从而诱发 Full GC;二是新生代 GC 耗时大幅度增加


3). Survivor 设置过小


导致对象从 eden 直接到达旧生代


4). Survivor 设置过大


导致 eden 过小,增加了 GC 频率


一般说来新生代占整个堆 1/3 比较合适


GC 策略的设置方式


1). 吞吐量优先 可由-XX:GCTimeRatio=n 来设置


2). 暂停时间优先 可由-XX:MaxGCPauseRatio=n 来设置


6. JVM 内存管理,JVM 的常见的垃圾收集器,GC 调优,Minor GC ,Full GC 触发条件(像是必考题)


GC 调优:


GC 日志分析


调优命令


调优工具


调优命令


Sun JDK 监控和故障处理命令有 jps jstat jmap jhat jstack jinfo


jps,JVM Process Status Tool,显示指定系统内所有的 HotSpot 虚拟机进程。


jstat,JVM statistics Monitoring 是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据。


jmap,JVM Memory Map 命令用于生成 heap dump 文件


jhat,JVM Heap Analysis Tool 命令是与 jmap 搭配使用,用来分析 jmap 生成的 dump,jhat 内置了一个微型的 HTTP/HTML 服务器,生成 dump 的分析结果后,可以在浏览器中查看


jstack,用于生成 java 虚拟机当前时刻的线程快照。


jinfo,JVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。


调优工具


常用调优工具分为两类,jdk 自带监控工具:jconsole 和 jvisualvm,第三方有:MAT(Memory Analyzer Tool)、GChisto。


jconsole,Java Monitoring and Management Console 是从 java5 开始,在 JDK 中自带的 java 监控和管理控制台,用于对 JVM 中内存,线程和类等的监控


GC 触发的条件有两种。(1)程序调用 System.gc 时可以触发;(2)系统自身来决定 GC 触发的时机。


要完全回收一个对象,至少需要经过两次标记的过程。


第一次标记:对于一个没有其他引用的对象,筛选该对象是否有必要执行 finalize()方法,如果没有执行必要,则意味可直接回收。(筛选依据:是否复写或执行过 finalize()方法;因为 finalize 方法只能被执行一次)。


第二次标记:如果被筛选判定位有必要执行,则会放入 FQueue 队列,并自动创建一个低优先级的 finalize 线程来执行释放操作。如果在一个对象释放前被其他对象引用,则该对象会被移除 FQueue 队列。


Minor GC ,Full GC 触发条件


Minor GC 触发条件:当 Eden 区满时,触发 Minor GC。


Full GC 触发条件:


(1)调用 System.gc 时,系统建议执行 Full GC,但是不必然执行


(2)老年代空间不足


(3)方法区空间不足


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


(5)由 Eden 区、From Space 区向 To Space 区复制时,对象大小大于 To Space 可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小


7. java 内存模型


与 JVM 内存模型不同。


Java 内存模型即 Java Memory Model,简称 JMM。JMM 定义了 Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式。JVM 是整个计算机虚拟模型,所以 JMM 是隶属于 JVM 的。


Java 内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


享变量进行同步。


Java 线程之间的通信采用的是过共享内存模型,这里提到的共享内存模型指的就是 Java 内存模型(简称 JMM),JMM 决定一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM 定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。


8. 线程池的工作原理(谈到多线程高并发大几率会问它)


1.先讲下作用


减少资源的开销 可以减少每次创建销毁线程的开销


提高响应速度 由于线程已经创建成功


提高线程的可管理性


2.讲实现


线程池主要有两部分组成,多个工作线程和一个阻塞队列。


工作线程是一组已经处在运行中的线程,它们不断地向阻塞队列中领取任务执行。而 阻塞队列用于存储工作线程来不及处理的任务。


3.细分讲下线程的组成


创建一个线程池需要要的一些核心参数。


corePoolSize:基本线程数量 它表示你希望线程池达到的一个值。线程池会尽量把实际线程数量保持在这个值上下。


maximumPoolSize:最大线程数量 这是线程数量的上界。 如果实际线程数量达到这个值: 阻塞队列未满:任务存入阻塞队列等待执行 阻塞队列已满:调用饱和策略 。


keepAliveTime:空闲线程的存活时间 当实际线程数量超过 corePoolSize 时,若线程空闲的时间超过该值,就会被停止。 PS:当任务很多,且任务执行时间很短的情况下,可以将该值调大,提高线程利用率。


timeUnit:keepAliveTime 的单位


runnableTaskQueue:任务队列


存放任务的阻塞队列,可以有如下几种选择:


ArrayBlockingQueue 它是一个由数组实现的阻塞队列,FIFO。


LinkedBlockingQueue 它是一个由链表实现的阻塞队列,FIFO。 吞吐量通常要高于 ArrayBlockingQueue。fixedThreadPool 使用的阻塞队列就是它。 它是一个无界队列。


SynchronousQueue 它是一个没有存储空间的阻塞队列,任务提交给它之后必须要交给一条工作线程处理;如果当前没有空闲的工作线程,则立即创建一条新的工作线程。 cachedThreadPool 用的阻塞队列就是它。 它是一个无界队列。 PriorityBlockingQueue 它是一个优先权阻塞队列。


handler:饱和策略 当实际线程数达到 maximumPoolSize,并且阻塞队列已满时,就会调用饱和策略。


AbortPolicy 默认。直接抛异常。 CallerRunsPolicy 只用调用者所在的线程执行任务。 DiscardOldestPolicy 丢弃任务队列中最久的任务。 DiscardPolicy 丢弃当前任务。


4.运行机制


当有请求到来时:


1.若当前实际线程数量 少于 corePoolSize,即使有空闲线程,也会创建一个新的工作线程;


2 若当前实际线程数量处于 corePoolSize 和 maximumPoolSize 之间,并且阻塞队列没满,则任务将被放入阻塞队列中等待执行;


3.若当前实际线程数量 小于 maximumPoolSize,但阻塞队列已满,则直接创建新线程处理任务;


4.若当前实际线程数量已经达到 maximumPoolSize,并且阻塞队列已满,则使用饱和策略。


9. NIO 底层原理


1 概念:


NIO 核心是 同步非阻塞,解决传统 IO 的阻塞问题。操作对象是 Buffer。 NIO 的核心是 IO 线程池. NIO 中的 IO 多路复用调用系统级别的 select 和 poll 模型,由系统进行监控 IO 状态,避免用户线程通过反复尝试的方式查询状态。


Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有 I/O 请求时才启动一个线程进行处理。


2.工作原理:


由一个专门的线程来处理所有的 IO 事件,并负责分发。


事件驱动机制:事件到的时候触发,而不是同步的去监视事件。


线程通讯:线程之间通过 wait,notify 等方式通讯。保证每次上下文切换都是有意义的。减少无谓的线程切换。


3.通信模型是怎么实现的呢?


java NIO 采用了双向通道(channel)进行数据传输,而不是单向的流(stream),在通道上可以注册我们感兴趣的事件。


四种事件


服务端接收客户端连接事件 SelectionKey.OP_ACCEPT(16)


客户端连接服务端事件 SelectionKey.OP_CONNECT(8)


读事件 SelectionKey.OP_READ(1)


写事件 SelectionKey.OP_WRITE(4)


服务端和客户端各自维护一个管理通道的对象 selector,该对象能检测一个或多个通道 (channel) 上的事件。以服务端为例,如果服务端的 selector 上注册了读事件,某时刻客户端给服务端发送了一些数据,阻塞 I/O 这时会调用 read()方法阻塞地读取数据,而 NIO 的服务端会在 selector 中添加一个读事件。服务端的处理线程会轮询地访问 selector,如果访问 selector 时发现有感兴趣的事件到达,则处理这些事件,如果没有感兴趣的事件到达,则处理线程会一直阻塞直到感兴趣的事件到达为止。


10. Spring IOC ,AOP 会问的两个原理,面试官经常会问看过源码吗?


概念:


IOC 是面向对象编程中的一种设计原则,IOC 理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦。对于 spring 框架来说,就是由 spring 来负责控制对象的生命周期和对象间的关系。 是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方。


实现原理:


通过反射机制+工厂模式实现的,在实例化一个类时,通过反射调用类中 set 方法将事先保存在 HashMap 中的类属性注入到类中。


控制反转就是:获得依赖对象的方式反转了。


1、依赖注入发生的时间

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
Java面试题原理和底层,java面试突击第二季