Offer来了 Java面试核心知识点精讲(原理篇)ISBN:978-7-121-37618-4
作者:王磊
页数:330页
阅读时间:2022-01-26
推荐指数:★★★★★
很不错的Java基础知识整理,其中包括JVM原理、多线程、数据结构和算法、设计模式、分布式等内容。
因为之前需要面试就买来看看,扎实一下基础知识。强烈推荐。
1. Java程序具体运行过程
- Java源文件被编译器编译成字节码文件。
- JVM将字节码文件编译成相应操作系统的机器码。
- 机器码调用相应操作系统的本地方法库执行相应的方法。
JVM包含如下:
- 一套字节码指令集
- 一个虚拟堆
- 一组程序寄存器
- 一个方法区
- 一个虚拟机栈
- 一个垃圾回收器
① 类加载器子系统将编译好的字节码(.class)文件加载到JVM
② 运行时数据区用于存储在JVM运行中产生的数据
③ 即时编译器用于将Java字节码编译成具体机器码
④ 本地接口用于调用操作系统的本地方法库完成具体的指令操作
JVM的具体架构图如下图所示:
JVM架构
2. JVM的内存区域
JVM的内存区域程序计数器:线程私有、无内存溢出,很小,存储当前线程执行的字节码行号指示器。
虚拟机栈:线程私有,描述Java方法的执行过程,在当前栈帧存储了局部变量表、操作数栈、处理动态连接、方法出口。
本地方法区:线程私有,Native方法服务。
堆:线程共享,创建对象产生的数据存储。
方法区:线程共享、永久代、存储常量、静态变量、类信息、即时编译器编译后的机器码、运行时常量池。内存回收主要针对常量池的回收和类的卸载,因此可回收的对象很少。
3. JVM 运行时内存
JVM运行时内存也叫作JVM堆,分为:新生代(占三分之一)、老生代(占三分之二)、永久代。
新生代又分为:Eden区(占十分之八)、SurvivorFrom区(占十分之一)、SurvivorTo区(占十分之一)。
新生代主要存储生命周期比较短、频繁创建的对象,因此会频繁的触发MinorGC。
Eden区:创建新对象时使用,内存不足会触发MinorGC
SurvivorFrom区:保留上一次MinorGC的幸存者
SurvivorTo区:上一次MinorGC时的幸存者作为这一次MinorGC的被扫描者。
老生代主要存储大对象,生命周期长的。因此采用MajorGC算法,不会频繁触发。
MinorGC算法(复制算法)
:
- 把Eden区和SurvivorFrom区中存活的对象复制到SurvivorTo区。根据年龄来判断(默认15岁),每次GC年+1。
- 清空Eden区和SurvivorFrom区中个对象。
-
将SurvivorTo区和SurvivorFrom区互换,原来的SurvivorTo区成为下一次GC时的SurvivorFrom区。
这种算法不会产生碎片,但是会导致空间缩小到原来的二分之一。
复制算法示意图
MajorGC算法(标记清除算法)
:
在进行MajorGC前会进行一次MinorGC,当老年代空间不足或无法找到足够的连续内存空间分配给新创建的大对象时,会触发MajorGC,容易产生内存碎片,会出现OutOfMemory。
永久代:主要存储Class、Meta(元数据)信息。GC不会在运行程序期间对永久代的内存进行清理,导致了永久代内存会随加载的Class文件增加而增加,会在加载过多时会OOM异常。
Java8 中永久代已经被元数据(元空间)取代。
元数据区并没有使用虚拟机内存,而是使用了OS本地内存,因此元空间大小不收JVM内存限制。
4. GC 算法
在垃圾回收之前需要确定哪些对象是垃圾,这里有两种方式:
引用计数法:
在Java操作对象时必须先获取对象的引用,所有添加一个引用时引用计数加1,删除时减1。当引用计数为0时就可以被回收。但是会出现循环引用问题,就是两个对象互相引用。
可达性分析:
先定义GC Roots对象,然后以这些GC Roots对象作为起点向下搜索,如果在GC Roots和一个对象之间没有可达路径,则该对象不可达就会被回收。
垃圾收集算法分为:标记清除算法、复制算法、标记整理算法、分代收集算法。
标记清除算法和复制算法可以看上面的描述。
标记整理算法:就是整合了标记清理的算法和复制算法,在标记阶段和标记清除算法的标记阶段一样,然后在标记完成之后将存活的对象移动到内存的另一端,并清理该端的对象。
标记整理算法示意图
分代收集算法:
针对不同的对象类型,JVM采用不同的垃圾回收算法。
5. 多线程
JVM线程与OS中的线程是相互对应的分为:
- 虚拟机线程:当JVM到达安全点时出现。
- 周期性任务线程:定时器调度线程来实现周期性任务。
- GC线程:不同垃圾回收活动。
- 编译器线程:在运行时将字节码动态编译成本地平台机器码是JVM跨平台具体实现。
- 信号分发线程:接收发送到JVM的信号并调用了JVM方法。
Java线程创建方式:
- 继承Thread类
- 实现Runnable接口
- 通过ExecutorService和Callable<Class>实现有返回值的线程
- 基于线程池
6. Java线程池的工作流程
Java线程池的7个核心参数:
参数 | 说明 |
---|---|
corePoolSize | 线程池中核心线程的数量 |
maximumPoolSize | 线程池中最大线程的数量 |
keepAliveTime | 当前线程数量超过corePoolSize时,空闲线程的存活时间 |
unit | keepAliveTime的时间单位 |
workQueue | 任务队列,被提交但尚未被执行的任务存放地方 |
threadFactory | 线程工厂,用于创建线程,可使默认的线程工厂或自定义线程工厂 |
handler | 由于任务过多或其他原因导致线程池无法处理时的任务拒绝策略 |
拒绝策略:
参数 | 说明 |
---|---|
AbortPolicy | 直接抛出异常,阻止线程正常运行 |
CallerRunsPolicy | 如果被抛弃的线程任务未关闭,则执行该任务 |
DiscardOldestPolicy | 移除线程队列中最早的一个线程任务 |
DiscardPolicy | 丢弃当前的线程任务而不做任何处理 |
实现RejectedExecutionHandler接口 | 自定义拒绝策略 |
具体的工作流程如下图:
Java线程池的工作流程
7. 线程的生命周期
线程的生命周期 线程的生命周期里面还有很多精华的内容,等你来发现哟~
网友评论