JAVA知识重点

【Git】

一、 Git常用命令

git init 初始化
全局设置
git config --global user.name “smallming”
git config --global user.email
“293882181@qq.com”
设置成功后会在C:\Users\smallming(此目录是Windows系统账号名)中出现.gitconfig
git add filename 添加文件到缓存区
git commit -m “备注” 提交到本地库
git remote add origin 仓库地址 设置远程仓库地址
git push -u origin master 推送到远程仓库
git clone 克隆远程仓库内容
git pull origin master 拉取内容
git rm 删除文件
git checkout -b 分支名 master 创建分支
git branch 查看本地分支
git push origin 本地分支名:远程分支名 推送分支
**git branch --set-upstream-to=origin/**分支名 关联本地和远程分支
git merge --no-ff 分支名 把分支合并到当前分支(注意先切换到当前分支)
git branch -d 分支名 删除本地分支
git push origin --delete 分支名 删除远程分支

二、 Git中常用分支及作用

**主分支(master):**主分支主要用于存放正式版本软件的。
**开发分支(Develop):**早晚提交时提交到这个分支。最后合并到主分支中。
**功能分支(feature):**一般为了开发特定功能而创建的分支。
**预发分支(release):**合并到Master之前做测试的。
修补bug分支(fixbug):软件发布后修补bug的分支。

【Linux】

三、 Linux常用命令(笔试或面试)

cd 进入目录
cd..返回上一级
pwd 打印当前目录
clear 清屏
ls/ll 显示当前目录内容
mkdir 创建新文件夹
mkdir -p 路径 : 如果路径中包含了不存在的路径 则自定创建一个
rm -r 文件夹路径 : 删除目录所有文件夹及文件夹中的子内容都需要通过输入y进行确认删除
rm -rf 文件夹路径:删除文件夹不需要确认
esc 退出编辑状态在退出编辑状态下 按两次d 表示删除当前行D+数字+回车便是删除数字行
q 退出 只有没有任何编辑操作的时候能使用
wq 保存并退出
**q!**强制退出Cat 文件路径
touch 创建新文件
cp 复制
mv
rm 删除
vi/vim 编辑
cat 查看内容内容
tail 查看文件后几行
tar 解压gzip文件
yum install 在线安装
ps aux|grep 查看进程
kill 杀掉进程
reboot重启

【JVM】

四、 请介绍一下HotSpot

在Java的官方文档中会发现,每个版本官方都提供了两个版本的文档地址。
官方文档地址: https://docs.oracle.com/javase/specs/index.html
请添加图片描述

官方对JVM提供的规范。何为规范,就是告诉我们想要开发JVM应该这样做。但是在JVM具体实现时可能有一定的偏差。
我们现在使用的都是官方对JVM规范的具体实现HotSpot。
请添加图片描述

在HotSpot实现过程中也提供一些参数,让开发者可以调试它(所谓的JVM调优其实就是调整设置这些参数)
HotSpot:https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html
但是市面上上还有一些其他厂商对JVM规范的具体实现

JVM名称 说明
HotSpot Oracle官方对JVM规范的实现
jRocket 曾经JVM的扛把子,号称最快的虚拟机,后被Oracle收购,和HotSpot整合
J9 IBM对JVM规范的实现
TaobaoVM HotSpot深度定制版
azul zing 商业收费版

五、 JVM内存结构

JVM是负责运行Java程序的虚拟计算机,是物理计算机中的一个进程。
JVM运行过程中为了方便管理,方便GC回收,所占内存区域被划分为多个部分。

1 Java HotSpot VM 内存结构图

请添加图片描述

1.1 源文件
源文件就是我们编写Java代码的文件。文件扩展名为.java
1.2 字节码文件
字节码文件是源文件编译后的文件。字节码文件是二进制文件,需要通过特定的工具才能查看。里面存放了源文件编译后的字节码指令。
1.3 类加载器 Class Loader
Java 程序运行时会由类加载器负责把.class的字节码文件装在到内存中,供虚拟机执行。
   加载 Loading
1. 启动类加载器 BootStrap Class Loader   :  负责从启动类中加载类。具有最高执行优先级。即:rt.jar等。

2. 扩展类加载器 Extension Class Loader  :  负责加载扩展相关类。即:jre/lib/ext 目录

3. 应用程序加载器 Application Class Loader  :  加载应用程序类路径(classpath)中相关类。
4. 链接 Linking
5. 校验 Verify  : 校验器会校验字节码文件是否正确。
6. 准备 Prepare  : 所有静态变量初始化并赋予默认值
7. 解析 Resolve  :符号引用被换成直接引用。
8. 初始化 Initialization  :  所有静态变量赋予初值,静态代码块执行。
1.4 执行引擎

运行时数据区的字节码会交给执行引擎执行

1. 解释器 Interpreter   : 解释器负责解释字节码文件。每次方法调用都会被重新解释。
2. JIT编译器  : JIT 即时编译器。对于多次被使用的方法会放入到本地内存中,下次就可以直接调用了。
3. 探测器  ; 负责探测多次被调用的代码。
4. 垃圾回收器 GC  : 负责回收不在被使用的对象。GC是JVM中非常重要的一块,在后面我们会单独讲解一下GC。
1.5 本地库接口
	在Java代码中使用native修饰的方法表示方法具体实现使用其他编程语言实现的。例如:C语言。通过本地库接口为Java程序提供调用其他语言的实现方案。
1.6 本地方法库
	所有的本地方法,通过本地库接口调用。
1.7 程序计数器
程序计数器简称:PC Register
程序计数器是一块较小的内存空间。记录了当前线程执行到的字节码行号。每个线程都有自己的程序计数器,相互不影响。如果是native方法,计数器为空。
1.8 虚拟机栈
虚拟机栈跟随线程创建而创建,所以每个线程都有一个虚拟机栈。
虚拟机栈中存储的是栈帧(frames),每个栈帧对应一个方法,每个栈帧都有自己的局部变量表、操作数栈、动态链接和返回地址等。当前正在执行的方法称为当前方法,当前方法所在的帧称为当前帧。方法执行时帧就是一个入栈操作,方法执行完成之后栈帧就是一个出站操作。
1.8.1 局部变量表
局部变量表存储的8大基本数据类型和返回值以及方法参数及对象的引用。	其中long和double占用2倍长度。
局部变量表就是一个数组,数组的长度在编译器确定。通过从0开始的索引调用局部变量表的内容。
对于类方法,从索引0开始连续N个作为方法传递。对于实例方法索引0存储的都是实例化方法的实例对象的引用。
1.8.2 操作数栈
操作数栈存在于栈帧中,其大小在编译期确定。
操作数栈中存储了class文件中虚拟机指令以及准备要传递的参数和接收对方的返回结果。
运行时常量池中数据以及局部变量表中得值都可以由操作数栈进行获取。
1.8.3 动态链接
方法·把符号转换为直接引用分为两种情况。在JVM加载或第一次使用转换时称为静态链接或静态解析。而在运行期间把符号转换为直接引用时就称为动态链接。
1.8.4 方法返回地址

方法返回地址分为两种情况:

1. 正常结束执行。例如碰见return关键字。调用程序计数器的值后当前栈帧直接出栈就可以了。
2. 异常结束。可能需要恢复上层方法的局部变量表和操作数栈,然后把返回值压如到栈帧的操作数栈中,之后调用程序计数器的值后获取到下条指令。
1.9 堆
堆是所有线程共享的,存储类的实例和数组。
堆是在虚拟机启动时创建的,由GC负责回收。
堆可以是一块不连续的内存空间。
在Java 8 中,String是存在于堆中的。

堆被分为二大部分:

在Java 7时分为:新生代(Young Generation)、老年代(Old Generation)。在HotSpot中使用永久代来实现方法区的规范。且新生代、老年代和永久代是连续的。
新生代又被分为Eden区、From Survivor区、To Survivor区。官方说明默认分配比例为8:1:1。但是使用jmap工具进行测试时发现比例为6:1:1。
在Java 8时把永久代替换为元空间(MetaSpace),也就是说在Java8中使用元空间来实现方法区。且在Java8中把元空间移植到本地内存上(Native Memory),其实在Java 7 时,部分数据已经移植到本地内存上了。例如:符号引用(Symbols)
1.10 方法区
1. 方法区是线程共享的。
2. 在虚拟机启动时自动创建方法区,方法区可以是一块不连续的内存空间。
3. 方法区可以理解为编译代码存储区。在方法区中存储每个类的结构、运行时常量池、字段、方法、构造方法。
4. 在JVM规范上方法区是一个独立的区域,但是在Java SE7 的HotSpot 上方法区使用永久代作为实现,永久代和堆是一块连续空间。在Java SE8的JVM规范实现上,HotSpot使用元空间实现方法区。
1.11 运行时常量池
运行时常量池存在于方法区。存储每个类或每个接口从编译时已知的数字文字到必须在运行时解析的方法和字段引用。
1.12 本地方法栈

本地方法栈主要是为了支持native方法。每个线程都有自己独立的本地方法栈。

六、 说一下JDK6、7、8中JVM内存结构的区别

请添加图片描述

七、 请说一下你知道的JVM启动参数

在Java学习的第一课一般都是写一个HelloWorld,然后通过命令行javac编译,在通过java.exe进行执行。java.exe就是运行java程序的工具,该工具有很多参数选项进行使用。
我们平时所说的JVM启动参数其实就是java.exe的options
Java 8 中HotSpot官方文档地址
https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html

1 总体语法

java [options] classname [args]

java [options] -jar filename [args]

javaw [options] classname [args]

javaw [options] -jar filename [args]

语法解释:
1. java和javaw为JDK里面带有的工具

请添加图片描述

2. **options**:选项。工支持6种选项。
3**. classname**:类名
4. **-jar** 参数
5. **filename** 文件名称
6. **args** 传递给主方法的参数。用空格分隔。

options分类

options分为6类,分别是:

1. Standard Options 标准选项。
2. Non-Standard Options 非标准选项
3. Advanced Runtime Options 高级运行时选项。控制Java HotSpot VM运行时行为。
4. Advanced JIT Compiler Options 高级JIT(即时编译器)编译器选项。使用JIT时优化参数,属于HotSpot专有选项,非JVM通用选项。
5. Advanced Serviceability Options 高级可维护性选项。提供了收集系统信息和执行大量调试的能力。
6. Advanced Garbage Collection Options 高级垃圾收集选项。控制HotSpot执行GC的方式。
其中3、4、5、6的参数都是以-XX:开头的

Standard Options(标准选项)

	标准选项是所有JVM实现都支持的选项。
1. -help
	启用帮助,显示所有支持的选项。
	也可以写成:java -?
2. -version
	打印版本号。
3. -ea
	启用断言。默认情况下断言是不启用的。
	assert expression;如果表达式为真继续运行,如果表达式为假报异常。

请添加图片描述

	assert expression1:expression2;如果expression1为真继续运行。如果表达式为假expression2作为异常信息。
4. -javaagent:jarpath[=options]
	加载指定的jar包。
5. -Dproperty=value
	设置系统属性值。在项目部署或Spring Boot项目中会使用到。
6. -jar filename
	运行指定的jar文件。
7. -verbose
	-verbose:gc 打印GC信息。用于诊断GC时使用。
	-verbose:class 打印载入类的相关信息。可用于诊断找不到类或类冲突时使用。
	-verbose:jni 输出native方法调用情况。可用于诊断native调用相关问题。
	Non-Standard Options(非标准选项)
	非标准选项是HotSpot专有选项。所有内容都是以-X开头(必须是大写)。
8 . -X
显示所有选项。

请添加图片描述

里面常用的就红色区域:

-Xms<size> 设置初始化Java堆大小

-Xmx<size> 设置最大堆大小。

-Xss<size>  设置Java线程堆栈大小。等效于-
XX:ThreadStackSize

-Xmn<size> 年轻代初始化和最大大小。建议年轻代占用整个堆的1/2~1/4之间。年轻代太小GC频率太高,年轻代太大会触发Full GC。也可以使用还可以使用-XX:NewSize设置初始大小和-XX:MaxNewSize最大大小

-Xloggc:filename 设置将gc信息写入到某个日志文件中。
高级运行时选项 Advanced Runtime Options
控制Java HotSpot VM运行时行为。所有的参数都是-XX: 开头。注意大小写。

-XX:+PrintCommandLineFlags
打印命令行JVM参数。默认不开启不打印。通过此内容可以查看默认配置,例如当前锁使用的虚拟机类型。等效于jinfo -flags pid

-XX:ThreadStackSize
设置线程堆栈大小。等效于-Xss

-XX:+TraceClassLoading
启用类加载跟踪。默认不开启打印。

-XX:+TraceClassLoadingPreorder
按照引用顺序跟踪所有加载的类。默认禁用

-XX:-UseBiasedLocking
禁用偏向锁。设置后对于一些大量无竞争的同步操作会明显提升性能。但对于某些具有锁的应用性能会降低。
高级JIT编译器选项 Advanced JIT Compiler Options

使用JIT时优化参数。

-XX:+AggressiveOpts
允许积极的使用性能优化功能。预计在后续版本设置为默认开启。目前是默认关闭的。

-XX:+BackgroundCompilation
启用后台编译,默认开启。如想取消使用-XX:-
BackgroundCompilation(等效于-Xbatch).

-XX:CICompilerCount=threads
设置用于编译的编译器线程数。默认情况下,服务器 JVM 的线程数设置为 2,客户端 JVM 的线程数设置为 1

-XX:CodeCacheMinimumFreeSpace=size
设置编译器最小空间。默认500KB。当剩余空间少于最小空间时,编译器停止工作。

-XX:InitialCodeCacheSize=size
设置初始代码缓存大小

-XX:+OptimizeStringConcat
启动String连接操作优化。默认启用。可使用-XX:-OptimizeStringConcat禁用
高级可维护性选项 Advanced Serviceability Options

提供了收集系统信息和执行大量调试的能力。按照官方文档一共就只有六个参数。

-XX:+HeapDumpOnOutOfMemoryError
当出现java.lang.OutOfMemoryError把堆中内容转存到当前目录文件中。默认禁止的。

-XX:HeapDumpPath=path
当设置了-XX:+HeapDumpOnOutOfMemoryError以后,转存文件路径。例如:-XX:HeapDumpPath=C:/log/java/java_heapdump.log

-XX:LogFile=path
设置写入日志数据的路径和文件名,例如-XX:LogFile=C:/log/java/hotspot.log

-XX:+PrintClassHistogram
默认禁止。当按Ctrl+Break时打印类的直方图。等效于:jmap -histo pid 命令

-XX:+PrintConcurrentLocks
默认禁止。打印Concurrent相关的锁。等效于:jstack -l

-XX:+UnlockDiagnosticVMOptions
默认禁止。解锁诊断VM选项内容。因为在JVM中某些参数必须诊断后才能赋值。
高级垃圾回收选项 Advanced Garbage Collection Options

控制HotSpot执行GC的方式。可选参数比较多,但也比较重要。里面部分参数为JVM优化常用参数。

-XX:ActiveProcessorCount= x
设置VM操作各种线程池(例如:ForkJoinPool)的CPU数量

-XX:+AggressiveHeap
默认禁止。启用堆优化。设置后将会根据计算机配置(RAM和CPU)将各种参数设置为最合适长时间运行的值。
-XX:+CMSClassUnloadingEnabled
默认开启。在使用标记清除垃圾收集齐(CMS)时开启类卸载。可使用减号禁用。

-XX:CMSInitiatingOccupancyFraction=num
设置老年代占用比例。取值(0-100),如果为负数,表示-XX:CMSTriggerRatio进行定义比例。

-XX:ConcGCThreads=threads
设置并发GC时可用线程数。默认情况下该值取决于JVM可用的CPU数量。

-XX:+DisableExplicitGC
默认禁用的。开启后将不会处理System.gc();但JVM仍会在必要时候进行GC。

-XX:+ExplicitGCInvokesConcurrent
默认禁用。通过System.gc()启用并发GC。必须与-XX:+UseConcMarkSweepGC一起启用。

-XX:G1HeapRegionSize=size
设置使用垃圾优先 (G1,garbage-first ) 收集器时 Java 堆细分到区域大小。

-XX:+G1PrintHeapRegions
默认禁止。打印哪些堆区域进行了回收,以及G1的使用情况。

-XX:InitialHeapSize=size
初始化堆大小。必须是01024的倍数且大于1MB。默认是根据系统配置自动选择。

-XX:InitialSurvivorRatio=ratio
初始化Suvivor区域的比例。

-XX:InitiatingHeapOccupancyPercent=percent
初始化堆所占空间触发GC的比例。默认45%。设置0表示不间断回收

-XX:MaxGCPauseMillis=time
单位毫秒。设置堆最大暂停时间。JVM有可能无法满足这个要求。默认没有设置。

-XX:MaxHeapSize=size
堆最大大小。等效于-Xmx

-XX:MaxHeapFreeRatio=percent
设置GC后最大堆空闲比例。如果超过这个比例将会缩小。默认值75%

-XX:MaxMetaspaceSize=大小
最大元空间大小。默认是根据系统所剩内容自动判断。

-XX:MaxNewSize=size
新生代最大大小

-XX:MaxTenuringThreshold=threshold
设置GC最大大小,即GC进行回收时年龄的大小。处于Survivor区域的对象每次GC后年龄都会增加1。最大值15.parallel collection默认值15.CMS默认值6.

-XX:MetaspaceSize=size
元空间大小。超过后进行GC。默认需要看系统可以内存大小。

-XX:NewRatio=ratio
年轻代和老年代比例。默认值为2.

-XX:NewSize=size
新生代大小。等效于-Xmn

-XX:ParallelGCThreads=threads
并行GC线程数。默认值取决于CPU。

-XX:+PrintGC
打印GC消息。默认禁用。

-XX:+PrintGCApplicationStoppedTime
打印GC时应用暂停时间

-XX:+PrintGCDetails
打印GC详情。默认禁用。

-XX:+PrintGCTimeStamps
打印GC时间戳

-XX:+ScavengeBeforeFullGC
在每次FullGC之前先对年轻代进行GC。默认开启的。且Oracle不建议禁用。

-XX:SurvivorRatio=ratio
设置年轻代中Eden区和Survivor区的比例。默认值是8.但是经过测试发现是打印的是8,实际比例为6.

-XX:TargetSurvivorRatio=percent
设置年轻代GC后Survivor区域的比例。

-XX:+UseAdaptiveSizePolicy
默认启用。使用自适应大小策略。如果想关闭,可以使用减号。关闭后必须显示设置 -XX:SurvivorRatio

-XX:+UseG1GC
默认禁用,根据计算机配置和JVM类型自动选择。配置后表示启动G1垃圾收集器。适用于服务端的垃圾收集器。主要是针对内存比较大的情况。G1可以尽可能的满足GC暂停时间要求,同时保证良好的吞吐量。在使用G1收集器的时候建议堆大小至少6GB以上。

-XX:+UseGCOverheadLimit
默认启用的。JVM限制在抛出OutofMemoryError之前GC所花费的比例。如果GC花费时间超过98%,而堆恢复低于2%则抛出OutOfMemoryError

-XX:+UseParallelGC
默认禁用。配置表示启用并行GC。如果开启会自动-XX:+UseParallelOldGC。除非显示禁用了。对于64位平台,默认GC类型。

-XX:+UseParallelOldGC
默认禁用。配置表示启用并行老年代GC。如果开启会自动启用-XX:+UseParallelGC

-XX:+UseParNewGC
默认禁止。启动年轻代并行GC。在JDK8 中如果希望启用年轻代GC时推荐使用这个选项,而不是XX:+UseConcMarkSweepGC

-XX:+UseConcMarkSweepGC
默认禁止,JVM根据计算机配置自动选择合适的GC。在老年代启用CMS垃圾回收器Oracle建议在吞吐量(-XX:+UseParallelGC)垃圾收集器无法满足应用程序延迟要求时使用CMS垃圾收集器。当开启此选项后自动开启-XX:+UseParNewGC。并且在JDK8中不允许-XX:+UseConcMarkSweepGC-XX:-UseParallelGC组合

-XX:+UseSerialGC
启用串行GC。默认禁止。但是对于小型简单应用,这种GC是较佳选择。客户端默认GC类型。

-XX:+UseStringDeduplication
G1回收器专有选项。默认禁止。配置后表示启用字符串重复删除。也就是说允许多个字符串对象指向同一个堆中字符串对象。

八、 GC是如何判断对象已经死亡(是垃圾)

引用计数(已淘汰)
引用计数算法就是看对象是否被引用。如果引用则对象计数器加一。如果释放引用计数器减一。但是引用计数算法最大的问题就是循环引用问题。当出现循环引用时对象计数器至少为1.这时候对象可能已经是垃圾了,但是无法被回收。

请添加图片描述

根可达算法(Root Searching)

达可根算法没有引用计数算法中循环引用无法被回收的问题。
其主要思路是通过一系列名为GC Roots的对象作为根,从根开始往下搜索,搜索过程经过的路径称为引用链(Reference Chain),当一个对象到达GC Root时表示当前对象还在使用,如果没有引用的或者和其他非GC Roots循环引用的内容都是垃圾。静态变量、线程变量、常量池、JNI(指针)都是GC Roots

请添加图片描述

九、 请说一下你知道的GC算法

标记清除算法(Mark-sweep)

首先标记出所有需要回收的对象。标记完成后统一回收所有标记的对象。
缺点:
效率低。碎片多。
请添加图片描述

复制算法(coping)

**目的:**主要是为了解决标记清除算法碎片问题。
**步骤:**内存按照容量分为大小相等的两块。每次只使用一块。当一块使用完成后,把存活的对象复制到另一个空间,然后把空间一次清除掉。
**缺点:**可用内存减少。

标记压缩算法(Mark-Compact)

又叫标记整理算法。
和标记清除算法有点类似。主要区别是标记完成后并不会直接清除,而是把所有不回收对象先向一端移动,然后在清除掉边界外面的对象。这样就不会产生内存碎片。
请添加图片描述

分代收集算法

把堆分为新生代和老年代。新生代采用一种算法,老年代采用采用算法。具体新生代和老年代采用的算法需要看使用哪种垃圾回收器。

十、 请说一下你知道GC的种类
1 总表说明
请添加图片描述

这些内容可以组合关系

请添加图片描述

十一、 请详细介绍下GC中各种垃圾回收器

1、 Serial、Serial Old 串行收集器

1.1 Serial 收集器
	起源于JDK 1.3,单线程执行,每次回收必须STW。
	应用场景:虚拟机在client模式下默认的GC。
	优点:简单高效。
1.2 Serial Old收集器
	老年代收集器。标记整理算法。单线程。主要应用在client模式下老年代收集。在JDK1.5之前可以与Parallel Scavenge配合使用。可作为CMS的备选。

2 ParNew收集器

	Serial 收集器多线程版本,用于收集新生代。可与CMS配合使用。
	ParNew可以并行执行,主要为了减少STW的时间,加快程序响应,给用户提供良好的体验。

3 Parallel Scavenge收集器

	新生代收集器。采用复制算法。可以并行执行。
	优点:
	具备自适应调节能力。-XX:+UseAdaptiveSizePolicy
	主要解决吞吐量问题。也被称为“吞吐量优先”收集器。即吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间),虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。高吞吐量可以高效的利用CPU时间,尽快完成运算任务。

4 Parallel Old收集器

	老年代收集器。标记整理算法。多线程。JDK 1.6中出现。

5 CMS收集器(Concurrent Mark-Sweep Collector)

5.1 介绍
		主要为了减少STW时间。
5.2 步骤
	采用标记清除算法:
	初始标记:初始标记只是标记下GC Root能够关联的对象。速度很快。需要STW
	并发标记:进行GC Roots Tracing的过程
	重新标记:修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录
	并发清除:并发的清除对象。
5.3 优缺点

优点:

	并发收集。低停顿。

缺点:

	对CPU非常敏感,对于CPU大于4个时要求并发收集时使用的线程数不等于1/4。但随着CPU增加而下降。
可能产生浮动垃圾。因为CMS清理阶段程序还在运行,所以就可能产生新的垃圾,这部分垃圾只能等到下次才能被清理。所以称为浮动垃圾。
可能产生大量空间碎片。

6 G1收集器(garbage-first)

6.1 介绍
JDK8中主推的收集器。属于CMS的替代品。
G1收集器时堆中的年轻代和老年代只是逻辑上的概念,实际上把堆(一块连续内存)分为很多Region(分区)每个分区里面又被分为多个卡片(Card)。所以里面可能有很多年轻代和老年代。G1收集器里面多了一个新的概念:humongous(巨型对象)。当对象达到或超过Region一半时称为巨型对象。举行对象独占一个或多个连续的Region。
6.2 步骤:
	1. 初始标记:初始标记阶段仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值。此过程需要STW,但是耗时很短。
	2. 并发标记:并发标记阶段是从GC Root开始对堆中对象进行可达性分析,找出存活的对象。此过程耗时可能较长于用户操作并发执行,不需要STW。
	3. 最终标记。标记因为并发标记时用户执行产生的垃圾。需要STW(也可以并行)
	4. 筛选回收。对各个Region收回价值和时间进行计算,筛选出符合用户设定的预期回收时间。

十二、 G1收集器和CMS收集器的区别

	1. G1是用在新生代和老年代同时使用。CMS是老年代收集器。

	2. G1是Java8主推的收集器。CMS是java5出现的收集器。
	
	3. G1的STW时间可由用户设定,在筛选回收过程“可预测”的想办法满足设定要求。CMS是尽可能的减少STW时间
	
	4. G1使用的是标记整理算法,CMS使用的是标记清除算法(所以可能有内存碎片)。

	5. G1回收的流程是初始标记、并发标记、最终标记、筛选回收。CMS的流程是:初始标记、并发标记、重新标记、并发清除。

十三、 请说一下如何进行JVM调优

想要进行JVM调优一定是程序运行过程中不能满足生产要求。否则程序运行非常流畅、非常稳定也没有必要去调优。所以JVM默认值是最好的选择。

JVM调优总体思路是:

	1. 服务器硬件配置能高则高。
	
	2. GC类型要选择好合适的类型。
	
	3. 减少GC频率和Full GC的次数。实现较高的吞吐量或较低延迟。
服务器硬件配置能高则高

理论上讲服务器配置越高,服务器的性能越好。JVM性能自然也会更高。但是一般情况下服务器的配置都是固定的。即使不是固定的单机硬件也有瓶颈。
所以一般都是在硬件配置固定的情况下尽量实现使用更少的内存来获取高吞吐量或较低延迟。

GC类型要选择好合适的类型
GC的类型选择也是很重要的事情。

单核或客户端模式选择serial+serial Old 组合即可。

多核64位系统选择Parallel Scavenge+Parallel Old 模式。吞吐量表现非常优秀。

如果对于较低延迟较高的应用可选择G1回收器。
减少GC频率和Full GC次数
减少GC频率
新生代的大小(-Xmn-XX:NewSize+-XX:MaxNewSize)直接影响GC频率。GC频率太高会导致JVM性能下降。

但是要注意:在堆大小固定的情况下,新生代大小越大,老年代大小越小。
减少Full GC 次数
当老年代满了以后会进行Full GC,所以增加老年代大小可以减少Full GC 的次数。

但是要注意:在堆大小固定的情况下,老年代越大,新生代越小。

所以默认情况下新生代和老年代的比例12-XX:NewRatio=)是Java官方通过不断尝试,不断测试出来的最优比例,在没有特殊要求的情况下可以使用这个比例。
JVM性能明显下降了,如何进行分析
		可以借助各种技术或工具进行观察。
日志
可以通过 -XX:+PrintGCDetails-Xloggc:/data/jvm/gc.log 把GC日志打印出来。
堆栈错误信息
当发生OutOfMemoryError后可以使用-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=path把堆信息转存下来。
线程快照
	jstack pid 打印某个时间点的线程快照。
JDK里面带的其他工具
		jconsole 可视化控制台工具,查看内存等。
		
		jmap 堆内存查看工具。
		
		jstat 虚拟机状态查看。
		
		jvisualvm 和jconsole类似,功能稍微强大一点。
分析完成后如何尝试调优

JVM调优是一个经验的,并没有一个固定答案。同一个项目在不同服务器上运行可能调优方案差别就很大。
当分析后发现GC频率过高或Full GC 次数过多可以从两方面入手:

1. 尝试修改新生代,老年代,元空间大小。及新生代中Eden和survivor的比例。但是最好不能全动,需要一点一点增加或减少根据配置后的效果再次修改。
		个人建议:JVM默认配置都官方经过多少次尝试给出的方案,能不动就不动。

2. 检查代码。很多时候是因为代码问题导致JVM性能下降。
		(1)	避免创建大对象或大数组。因为大对象和大数组可能直接进入到老年代。增加Full GC 的次数。
		(2)	避免一次做大量数据操作。可以考虑分页或分批完成。
最后的建议
JVM 并不是我们写的,我们只是使用它。

HotSpot之所以能够调优也是因为它给我们提供了一系列参数选项和工具,只要我们能够清楚JVM内存结构图、GC类型、GC算法、JVM参数就可以根据自己应用实际情况进行尝试调优。
JVM调优是无法给出固定答案的,因为一点点小变化可能导致调优方案不一样。所以只要具备调优的思想就可以应付所有的情况了。

另外优秀的代码也是调优的有段。好的代码可以大大减少调优的成本。

十四、 全盘负责委托机制

这是类加载的一种机制。即:当一个ClassLoader加载一个类时,除非明确指定,否则这个类所依赖和引用的类也由这个ClassLoader进行加载。

十五、 双亲委派机制

双亲委派机制在代码中体现可以通过java.lang.ClassLoader中的loadClass()方法进行查看。

请添加图片描述

断点查看可以总结出来下面流程,需要注意的是:

1. 委派的过程就是一层一层向上找的过程。只要当前加载器加载过,就不会重新加载。如果没有加载过,会向上寻找是否加载过。
2. 当加载到Bootstrap ClassLoader后会一层一层的向下判断是否可以进行加载,如果能加载则加载。如果不能加载向下一层寻找下个加载器是否能加载。如果到最后一层都无法加载则报ClassNotFoundException
. 

请添加图片描述

好处:避免重复加载(加载一次就不加载)和避免核心类的串改(优先Bootstrap classloader

十六、 类加载的生命周期/类加载机制

在这里插入图片描述

类加载的过程(类的生命周期)就是

		1. 加载:加载.class文件到内存。包含自定义类的字节码文件和依赖及引用的字节码文件。
		
		2. 链接:包含校验文件、静态变量申请内存赋初值、符号引用变成直接引用。
		
		3. 初始化:执行静态代码块和静态变量赋值。
		
		4. 运行。
		
		5. 卸载。

【MySQL】

十七、 MySQL行列转置/MySQL行列转换(笔试题)

要求:
把下面数据转换

在这里插入图片描述

转换成下面效果
在这里插入图片描述

创建表及测试数据

create table student(
	id int(11) primary key auto_increment,
	name varchar(20),
	subject varchar(20),
	score double
);

insert into student values(1,'张三','语文',20);
insert into student values(2,'张三','数学',30);
insert into student values(3,'张三','英语',40);
insert into student values(4,'李四','语文',50);
insert into student values(5,'李四','数学',60);
insert into student values(6,'李四','英语',70);

可以使用if(表达式,值1,值2)函数。如果表达式成立返回值1,否则返回值2。其中值可以是列。

select 
	max(if(subject='语文',score,0)) 语文,
	max(if(subject='数学',score,0)) 数学,
	max(if(subject='英语',score,0)) 英语,
	name 
from student group by name;

也可以使用case 条件 when 条件取值 then 结果 … else 结果 end

select 
	max(case subject when '语文' then score else 0 end) 语文,
	max(case subject when '数学' then score else 0 end)  数学,
	max(case subject when '英语' then score else 0 end)  英语,
	name 
from student group by name;

十八、 请说一下MySQL支持的存储引擎?

MySQL 可以通过 show engines 查看所有支持的存储引擎。
在MySQL中默认支持的存储引擎有8个。 federated 默认是不启用的。主要用来提供对远程MySQL服务器上面的数据的访问接口。

  1. InnoDB
    默认的存储引擎,也是所有存储引擎中唯一支持事务、XA协议、保存点的存储引擎。
  2. MyISAM
    基于ISAM(Indexed Sequential Access Method目前已经废弃)的存储引擎,特点是查询效率较高。但不支持事务和容错性。
  3. MEMORY
    纯内存型型存储引擎。所有数据都在内存中,硬盘只存储.frm文件。所以当MySQL宕机或非法关闭时只生效表结构。当然了,由于所有数据都在内存上,所以相对来说性能较高。
  4. MRG_MYISAM
    以前也叫MERGE,简单理解就是对MyISAM表做了特殊的封装,对外提供单一访问入口,减少程序的复杂性。
  5. ARCHIVE
    存储引擎主要用于通过较小的存储空间来存放过期的很少访问的历史数据。ARCHIVE表不支持索引,通过一个.frm的结构定义文件,一个.ARZ的数据压缩文件还有一个.ARM的meta信息文件。由于其所存放的数据的特殊性,ARCHIVE表不支持删除,修改操作,仅支持插入和查询操作。
  6. BLACKHOLE
    俗称“黑洞”存储引擎。是一个非常有意思的存储引擎。所有的数据都是有去无回。
  7. CSV
    存储引擎实际上操作的就是一个标准的CSV文件,他不支持索引。起主要用途就是大家有些时候可能会需要通过数据库中的数据导出成一份报表文件,而CSV文件是很多软件都支持的一种较为标准的格式,所以我们可以通过先在数据库中建立一张CSV表,然后将生成的报表信息插入到该表,即可得到一份CSV报表文件了。
  8. PERFORMANCE_SCHEMA
    从MySQL 5.6新增的存储引擎。主要用于收集一些系统参数。

官方文档参考地址:https://dev.mysql.com/doc/refman/8.0/en/storage-engines.html

十九、 MySQL支持的日志类型?

MySQL 官方文档中说明MySQL共有六种日志类型
在这里插入图片描述

  1. 错误日志(Error log):记录MySQL运行过程中较为严重的警告和错误信息,以及MySQL启动和关闭的详细信息。可通过show variables like ‘%log_error%’;查看
  2. 通用查询日志(General query log):是记录建立的客户端连接和执行的语句。可通过通过show variables like ‘%general%’ 查看通用查询日志是否开启,默认是不开启的。
  3. 二进制日志(Binary log):包含所有更新数据或表结构(新增、删除、修改、改表等)SQL 信息的记录。可通过show variables like ‘%log_bin%’;查看,由于文件是二进制文件,所以是无法直接使用记事本查看的。在搭建MySQL主从时就要求开始二进制日志。
  4. 中继日志(Relay log):在MySQL主从复制实现中,记录从数据库数据改变。
  5. 慢查询日志(Slow query log):记录所有执行时间超过long_query_time秒的所有查询或不适用于索引的查询。可通过show variables like ‘%quer%’;查看。可通过log_queries_not_using_indexes 查看是否记录没有通过索引的SQL。
  6. DDL日志(DDL log):记录由影响表分区的数据定义语句生成的元数据操作。例如 ALTER TABLE t3 DROP PARTITION p2,我们必须确保完全删除分区并将其定义从表的分区列表中删除 t3。MySQL 使用此日志从分区元数据操作中间发生的崩溃中恢复。

官方文档参考地址: https://dev.mysql.com/doc/refman/8.0/en/server-logs.html

二十、 MySQL 的SQL语句执行流程

在这里插入图片描述

  1. **连接管理与安全验证:**MySQL有连接池(Connection Pool)管理客户端的连接。客户端连接后会验证用户名、密码、主机信息等
  2. 缓存(Cache&Buffer):缓存中存储了SQL命令的HASH,直接比对SQL命令的HASH和缓存中key是否对应,如果对应,直接返回结果,不再执行其他操作。由于缓存的是SQL的HASH,所以根据Hash特性SQL中空格等内容必须完全一样。缓存里面包含表缓存、记录缓存、权限缓存等。查询语句执行完成后会把查询结果缓存到缓存中。在MySQL中查询缓存默认不开启。考虑到查询缓存性能瓶颈问题,从MySQL8开始已经不支持查询缓存了。
  3. **解析器(Parser)**主要作用是解析SQL命令。将SQL命令分解成数据结构(解析树),后续的操作都是基于这个结构的。如果在分解过程中遇到错误,出现SQL解析错误。解析时主要检查SQL中关键字,检查关键字是否正确、SQL中关键字顺序是否正确、引号是否对应是否正确等。
  4. 预处理器:根据解析器的解析树,进一步检查表是否存在、列是否存在、名字和别名是否有歧义等。
  5. **优化器(Optimizer):**根据官网说明在执行SQL查询时会根据开销自动选择最优查询方案。采用“选择-投影-连接”的策略。先选择where中的行数。同时先选择要选择的列,而不是全部列,最后把内容合并到一起。
  6. **执行器:**包含执行SQL命令。获取返回结果。生成执行计划等。
  7. **存储引擎:**访问物理文件的媒介

MySQL中SQL执行流程文字说明

1. 客户端向服务器端发送SQL命令和连接参数

2. 服务器端连接模块连接并验证

3. 缓存模块解析SQL为Hash并与缓存中Hash表对应。如果有结果直接返回结果,如果没有对应继续向下执行。如果是MySQL 8 是没有查询缓存的。

4. 解析器解析SQL为解析树,检查关键字相关问题,如果出现错误,报SQL解析错误。如果正确,继续执行

5. 预处理器对解析树继续处理检查表、列别名等,处理成功后生成新的解析树。

6. 优化器根据开销自动选择最优执行计划,生成执行计划

7. 执行器执行执行计划,访问存储引擎接口

8. 存储引擎访问物理文件并返回结果

9. 如果开启查询缓存,缓存管理器把结果放入到查询缓存中。

10. 返回结果给客户端

二十一、 什么是执行计划?MySQL中执行计划类型有哪些?

执行计划:在MySQL中可以通过explain关键字模拟优化器执行SQL语句,从而知道MySQL是如何处理SQL语句的。
从好到坏排序。一般要求至少是range级别,最好能达到ref级别

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL 

给定表结构如下:
在这里插入图片描述

建表SQL语句

create table teacher(
	tid int(11) primary key auto_increment,
	tname varchar(20)
);
insert into teacher values(1,'老师1');
insert into teacher values(2,'老师2');

create table student(
	sid int(11) primary key auto_increment,
	sname varchar(20),
	stid int(11),
	constraint  fk_t_s foreign key (stid) references teacher(tid)
);

insert into student values(1,'学生1',1);

1.1. system:逻辑表中只有一行数据,属于const的特例。如果物理表就一行数据为ALL

explain select * from (select * from student  limit 0,1) t;

1.2. const:查询结果最多有一个匹配行。因为只有一行,所以可以被视为常量。const查询速度非常快,因为只读一次。一般情况下把主键或唯一索引作为唯一条件的查询都是const

explain select * from student where sid = 1

1.3. eq_ref: 查询时前表每次匹配到后表唯一一行数据(如果外键列有null时类型降低为ref),对于后表来说就是eq_ref。。但是需要注意,如果另一个表中所有行都被读取到了,就是ALL了。

explain select * from student s,teacher t where s.stid=t.tid;

ref:查询时,不是使用唯一索引或主键时的其他索引作为查询条件

explain select * from student where stid=1;
explain select * from student where stid=1 and sname='学生1';

1.4. fulltext: 只要是全文索引使用的就是fulltext类型。
1.5. ref_or_null:查询外检表时以外键列作为条件,搜索时包含null值。注意:只搜索外键列是null为ref

explain select * from student where stid=3 or  stid is null;

1.6. index_merge 索引合并优化。当使用索引合并优化时的类型。要求只能合并单表的索引查询结果。

alter table student add column (age int(11));
create unique index bbb on student(age);
insert into student values (2,'学生2',2,12);
insert into student values (3,'学生3',2,13);
explain select * from student where stid=1 or age=1;

1.7. unique_subquery 当eq_ref时部分包含子查询时的情况替换为unique_subquery

explain select t.tid in (select s.sid from student s) from teacher t

1.8. index_subquery 子查询中使用了索引,但是没有使用唯一索引。

explain select t.tid in (select s.stid from student s) from teacher t

1.9. range:把这个列当作条件只检索其中一个范围。常见where从句中出现between、<、in等。主要应用在具有索引的列中

explain select * from student where sid between 1 and 5

1.10. index:Full Index Scan,index与ALL区别为index类型只遍历索引树。这通常为ALL块,因为索引文件通常比数据文件小。(Index与ALL虽然都是读全表,但index是从索引中读取,而ALL是从硬盘读取)

explain select count(*) from student;

1.11. ALL:Full Table Scan,遍历全表以找到匹配的行

explain select * from student where sname='学生';

官方文档参考地址:https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

二十二、 什么是索引,索引的优缺点有哪些?

1. 索引是什么

索引类似图书的目录,一种数据结构,通过索引可以快速的找到需要查询的内容。MySQL官方文档中说明MySQL在500W~800W数据以上时查询性能可能下降,所以在大量数据时建立索引提升查询性能是非常有必要的。

索引和数据都是存储在.idb文件(InnoDB引擎),默认MySQL使用B+Tree(InnoDB引擎)结构进行存储索引数据,也可以修改为Hash索引。
B+Tree就是基于B-Tree而来的,主要是非叶子节点只存储键的信息;数据都记录在叶子节点上;所有叶子节点都有都有一个链式指针。

在这里插入图片描述

2. 索引的优点

为什么要创建索引?这是因为,创建索引可以大大提高系统的查询性能。

第一、通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。 

第二、可以大大加快数据的检索速度,这也是创建索引的最主要的原因。 

第三、可以加速表和表之间的连接,特别是在实现数据的完整性方面特别有意义。 

第四、在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。 

第五、通过使用索引,可以在查询的过程中,使用查询优化器,提高系统的性能。

3. 索引的缺点

也许会有人要问:增加索引有如此多的优点,为什么不对表中的每一个列创建一个索引呢?这种想法固然有其合理性,然而也有其片面性。虽然,索引有许多优点, 但是,为表中的每一个列都增加索引,是非常不明智的。 这是因为,增加索引也有许多不利的一个方面:

第一、创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。 

第二、索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么需要的空间就会更大。 

第三、当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

4. 什么样的字段适合创建索引

索引是建立在数据库表中的某些列的上面。因此,在创建索引的时候,应该仔细考虑在哪些列上可以创建索引,在哪些列上不能创建索引。 一般来说,应该在具备下述特性的列上创建索引:

第一、在经常需要搜索的列上,可以加快搜索的速度; 

第二、在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构; 

第三、在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度; 

第四、在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的; 

第五、在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间; 

第六、在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。

建立索引,一般按照select的where条件来建立,比如: select的条件是where f1 and f2,那么如果我们在字段f1或字段f2上建立索引是没有用的,只有在字段f1和f2上同时建立索引才有用等

5. 什么样的字段不适合创建索引:

同样,对于有些列不应该创建索引。一般来说,不应该创建索引的这些列具有下述特点:

第一,对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。 

第二,对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。 

第三,对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。 

第四,当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。

二十三、 索引分类

可以通过show index from 表名,查询表中包含的索引。
给定表结构测试索引

create table demo(
	id int(11) primary key,
	col1 int,
	col2 int,
	col3 varchar(20)
);

1. 单列索引。就是给一个列添加索引。

1.1 普通索引:不考虑过多情况,主要是为了让查询更快一些。
	语法:create index 索引名 on 表名()
		例如:create index index1 on demo(col1);

1.2 唯一索引:列中值不可以重复,可以是null
	语法:create unique index 索引名 on 表名()
		例如:create unique index index2 on demo(col2);

1.3 主键索引:列中值不可以重复,又不可以为null。简单点理解不允许为null的列添加上唯一索引就是主键索引。

2. 组合索引。

给表中大于等于两个列添加索引。但是需要满足最左前缀,创建组合索引相当于创建了多个索引,一般把最常用的放在最左边。

		语法:create index
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薄荷先生。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值