Skip to content

Commit

Permalink
change image
Browse files Browse the repository at this point in the history
  • Loading branch information
NotFound9 committed Apr 22, 2020
1 parent b4db720 commit 029a406
Show file tree
Hide file tree
Showing 12 changed files with 345 additions and 39 deletions.
65 changes: 48 additions & 17 deletions docs/JVMBook.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
执行一个Java方法时虚拟机都会创建一个栈帧来存储局部变量表操作数栈等方法调用完毕后会对栈帧从虚拟机栈中移除

局部变量表中存储了Java基本类型对象引用可以是对象的存储地址也可以是代表对象的句柄等和returnAddress类型存储了一条字节码指令的地址)。
##### 本地方法栈
#### 本地方法栈

本地方法栈与Java虚拟机栈类似只不过是执行Native方法C++方法等)。

#### 程序计数器
Expand Down Expand Up @@ -45,9 +46,11 @@
![java对象创建流程](../static/20160505123459787.jpeg)

#### 1.类加载检查
当虚拟机遇到一条字节码**new**指令时会根据类名去**常量池**找类的**符号引用**,检查符号引用代表的类是否已加载解析和初始化过如果没有就执行相应的**类加载**过程

首先代码中new关键字在编译后会生成一条字节码new指令当虚拟机遇到一条字节码**new**指令时会根据类名去方法区**常量池**找类的**符号引用**,检查符号引用代表的类是否已加载解析和初始化过如果没有就执行相应的**类加载**过程

#### 2.分配内存

虚拟机从Java堆中分配一块大小确定的内存因为类加载时创建一个此类的实例对象的所需的内存大小就确定了),并且初始化为零值内存分配的方式有**指针碰撞****空闲列表**两种取决于虚拟机采用的垃圾回收期是否带有空间压缩整理的功能

##### 指针碰撞
Expand All @@ -58,29 +61,43 @@

如果垃圾收集器是CMS这种基于清除算法的收集器时Java堆中的空闲内存和已使用内存是相互交错的虚拟机会维护一个列表记录哪些可用哪些不可用分配时从表中找到一块足够大的空闲内存分配给实例对象并且更新表

#### PS:如何解决内存分配时的多线程并发竞争问题
内存分配不是一个线程安全的操作在多个线程进行内存分配是可能会存在数据不同步的问题所以有两种方法解决
##### 添加CAS锁
对内存分配的操作进行同步处理添加CAS锁配上失败重试的方式来保证原子性。(默认使用这种方式)。
##### 预先给各线程分配TLAB
预先在Java堆中给各个线程分配一块TLAB本地线程缓冲区内存每个线程先在各自的缓冲区中分配内存使用完了再通过第一种添加CAS锁的方式来分配内存。(是否启动取决于-XX:+/-UseTLAB参数)。

#### 3.对象初始化虚拟机层面
虚拟机会对对象进行必要的设置将对象的一些信息存储在Obeject header

#### 4.对象初始化Java程序层面
在构造一个类的实例对象时在Java程序层面会依次进行以下操作
在构造一个类的实例对象时遵循的原则是先静后动先父后子先变量后代码块构造器在Java程序层面会依次进行以下操作
* 初始化父类的静态变量如果是首次使用此类

* 初始化子类的静态变量如果是首次使用此类

* 执行父类的静态代码块如果是首次使用此类

* 执行子类的静态代码块如果是首次使用此类

* 初始化父类的实例变量

* 初始化子类的实例变量

* 执行父类的普通代码块

* 执行子类的普通代码块

* 执行父类的构造器

* 执行子类的构造器

#### PS:如何解决内存分配时的多线程并发竞争问题

内存分配不是一个线程安全的操作在多个线程进行内存分配是可能会存在数据不同步的问题所以有两种方法解决

##### 添加CAS锁

对内存分配的操作进行同步处理添加CAS锁配上失败重试的方式来保证原子性。(默认使用这种方式)。

##### 预先给各线程分配TLAB

预先在Java堆中给各个线程分配一块TLAB本地线程缓冲区内存每个线程先在各自的缓冲区中分配内存使用完了再通过第一种添加CAS锁的方式来分配内存。(是否启动取决于-XX:+/-UseTLAB参数)。

### 对象的内存布局

对象在内存中存储布局主要分为对象头实例数据和对齐填充三部分
Expand Down Expand Up @@ -216,29 +233,43 @@ GC Roots对象只有包括以下几种:

缺点

1.执行效率不稳定有大量对象时并且有大量对象需要回收时执行效率会降低
**效率不稳定**

2.内存碎片化会产生大量不连续的内存碎片。(内存碎片只能通过使用分区空闲分配链表来分配内存
执行效率不稳定有大量对象时并且有大量对象需要回收时执行效率会降低

**内存碎片化**

内存碎片化会产生大量不连续的内存碎片。(内存碎片只能通过使用分区空闲分配链表来分配内存

#### 标记-复制算法

就是将内存分为两块每次只用其中一块垃圾回收时将存活对象拷贝到另一块内存。(serial newparallel new和parallel scanvage垃圾收集器

缺点

1.存活率较高时需要很多复制操作销量会降低
**不适合存活率高的老年代**

存活率较高时需要很多复制操作效率会降低所以老年代一般不使用这种算法

**浪费内存**

2.会浪费一半的内存
会浪费一半的内存

解决方案是新生代的内存配比是Eden:From Survivor: To Survivor = 8:1:1

每次只使用Eden和From Survivor的空间将存活对象拷贝到To Survivor当空间不够时从老年代进行分配担保
每次使用时Eden用来分配新的对象From Survivor存放上次垃圾回收存活的对象只使用Eden和From Survivor的空间To Survivor是空的垃圾回收时将存活对象拷贝到To Survivor当空间不够时从老年代进行分配担保

####标记-整理算法

让存活对象往内存空间一端移动然后直接清理掉边界以外的内存。(parallel Old和Serial old收集器就是采用该算法进行回收的
就是让存活对象往内存空间一端移动然后直接清理掉边界以外的内存。(parallel Old和Serial old收集器就是采用该算法进行回收的

**吞吐量高**

移动时内存操作会比较复杂需要移动存活对象并且更新所有对象的引用会是一种比较重的操作但是如果不移动的话会有内存碎片内存分配时效率会变低所以由于内存分配的频率会比垃圾回收的频率高很多所以从吞吐量方面看标记-整理法高于标记-清除法所以强调高吞吐量的Parallel Scavenge收集器是采用标记整理法

**延迟高**

移动时内存操作会比较复杂需要移动存活对象并且更新所有对象的引用会是一种比较重的操作
但是由于需要移动对象停顿时间会比较长垃圾回收时延迟会高一些强调低延迟的CMS收集器一般是大部分时候用标记-清除算法当内存碎片化程度达到一定程度时触发Full GC会使用标记-整理算法清理一次

#### 分代收集算法

Expand Down
7 changes: 6 additions & 1 deletion docs/JavaBasic.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@

#### [10.Java中的内部类是怎么样的?](#Java中的内部类是怎么样的?)

#### [11.Java中的注解是什么?](#Java中的注解是什么)



### Java中的多态是什么

**多态**指的是相同类型的变量在调用通一个方法时呈现出多种**不同的行为特征**。而造成这一现象的原因在于Java中的变量有两个类型
Expand Down Expand Up @@ -672,4 +676,5 @@ OutClass.InnerClass object = new OutClass.InnerClass();
OutClass out = new OutClass();
OutClass.InnerClass object = out.new InnerClass();
```

### Java中的注解是什么
Java中的注解其实是
98 changes: 97 additions & 1 deletion docs/JavaJVM.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,100 @@

##### 虚引用

虚引用主要用于跟踪对象被垃圾回收的状态不能单独使用必须和引用队列联合使用
虚引用主要用于跟踪对象被垃圾回收的状态不能单独使用必须和引用队列联合使用

### JVM 内存区域分布是什么样的gc 发生在哪些部分

Java虚拟机的内存区域主要分为虚拟机栈本地方法栈程序计数器方法区垃圾回收主要是对堆中的对象进行回收方法区里面也会进行一些垃圾回收但是毕竟少主要是针对类型的卸载常量池中变量的回收

##### 虚拟机栈

主要是用于方法执行的每次执行方法时就会创建一个栈帧来存放局部变量表操作数栈等

局部变量表主要是存储方法的参数和创建的局部变量基本类型或者引用类型),它的大小在编译时就固定了方法有一个Code属性记录了需要的局部变量表的大小

操作数栈是一个栈主要用来做算术运算及调用其他方法时存储传参调用其他方法时当前方法栈帧的操作数栈会跟其他方法的局部变量表有一定的重叠主要便于共享这些传递参数节约内存空间。(最大深度也是编译时就计算好的。)

##### 本地方法栈

调用native方法时的栈

##### 程序计数器

跟虚拟机栈本地方法栈一样程序计数器也是线程私有的主要用来记录当前线程执行的字节码指令的行号

#####

用来存储对象和数据的区域被所有线程共享在物理上可以是不连续的

##### 方法区

方法区也是被线程共享的主要存放类型信息常量静态变量方法去中有一个运行时常量池

Java中的类在编译后会生成class文件class文件除了包含变量方法接口信息外还包含一个常量池表用于存放编译时生成的各种字面量和符号引用在类加载后字符流常量池会被存放在方法区中的运行时常量池中运行期间也会可以将新的常量添加到运行时常量池例如对String的实例调用intern方法



### 对象的创建过程是怎么样的

#### 1.类加载检查

首先在代码里面创建对象使用的new关键字在编译时会编译成new字节码指令然后Java虚拟机在执行这条指令时首先会根据类名去方法区中的运行时常量池查找类的符号引用检查**符号引用**对应的类是否已经加载如果没有加载那么进行类加载如果已经加载了那么进行内存分配

#### 2.内存分配

Java虚拟机会从堆中申请一块大小确定的内存因为类加载时创建一个此类的实例对象的所需的内存大小就确定了),并且初始化为零值根据采用的垃圾收集器的不同内存分配方式有两种

##### 指针碰撞

一些垃圾回收算法回收后的可用内存是规整只需要移动分界点的指针就可以内存分配

##### 空闲列表

一些垃圾回收算法回收后的可用内存是零散的与已使用的内存是相互交错的此时需要用一个列表来记录这些空闲的内存分配内存时找一块足够的内存使用。(一般来说使用标记-清除的垃圾算法是不规整的

#### 3.对象初始化虚拟机层面

Java虚拟机层面会对对象做一些初始化操作将对象的一些信息存储到Obeject header

##### 4.对象初始化代码层面

在Java程序层面对对象进行初始化在构造一个类的实例对象时遵循的原则是先静后动先变量后代码块构造器先父后子在Java程序层面会依次进行以下操作

- 初始化父类的静态变量如果是首次使用此类

- 初始化子类的静态变量如果是首次使用此类

- 执行父类的静态代码块如果是首次使用此类

- 执行子类的静态代码块如果是首次使用此类

- 初始化父类的实例变量

- 初始化子类的实例变量

- 执行父类的普通代码块

- 执行子类的普通代码块

- 执行父类的构造器

- 执行子类的构造器

### 怎么查询当前JVM使用的垃圾收集器
使用这个命令可以查询
java -XX:+PrintCommandLineFlags -version
我们在IDEA中启动的一个Springboot的项目默认使用的垃圾收集器参数是
-XX:+UseParallelGC
```
-XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
java version "1.8.0_73"
Java(TM) SE Runtime Environment (build 1.8.0_73-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.73-b02, mixed mode)
```
UseParallelGC参数会使用Parallel Scavenge+Serial Old的收集器组合进行内存回收
![img](../static/519126-20180623154635076-953076776.png)

另外这个命令可以查询到更加详细的信息

java -XX:+PrintFlagsFinal -version | grep GC
5 changes: 4 additions & 1 deletion docs/MySQLNote.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#### [索引是什么?](#索引是什么?)
#### [字符串索引和数字类型索引的区别?](#字符串索引和数字类型索引的区别?)
#### [union和union all的区别是什么?](#union和union)

#### [Join的工作流程是怎么样的怎么进行优化?](#Join的工作流程是怎么样的怎么进行优化)
#### [聚集索引是什么?](#聚集索引是什么?)
#### [联合索引是什么?](#联合索引是什么?)
Expand Down Expand Up @@ -348,7 +349,9 @@ https://blog.csdn.net/chai471793/article/details/99563704

union就是将两个SELECT语句查询的结果集合并(两个SELECT可以是同一个表也可以是不同表),如果需要排序在第二个SELECT语句后加ORDER BY语句会对所有结果进行排序

union默认是会去除重复的数据的如果需要不去重的结果那么应该使用union all
union默认是会去除重复的数据的会对结果集做去重处理union all不会做去重处理

所以union效率慢一些如果能确定结果不会重复或者需要不去重的结果那么应该使用union all效率会高一些

![](https://user-gold-cdn.xitu.io/2019/7/8/16bd188f482703e1)

Expand Down
Loading

0 comments on commit 029a406

Please sign in to comment.