This commit is contained in:
CyC2018 2018-12-18 23:01:48 +08:00
parent c6fe1de49a
commit 8c7aa37313
1239 changed files with 33534 additions and 408 deletions

BIN
docs.rar Normal file

Binary file not shown.

View File

@ -8,7 +8,7 @@
<!-- GFM-TOC -->
<div align="center"> <img src="../pics//011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png"/> </div><br>
<div align="center"> <img src="pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png"/> </div><br>
# 一、解决的问题
@ -20,9 +20,9 @@ Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程
虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。
<div align="center"> <img src="../pics//71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png"/> </div><br>
<div align="center"> <img src="pics/71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png"/> </div><br>
<div align="center"> <img src="../pics//7e873b60-44dc-4911-b080-defd5b8f0b49.png"/> </div><br>
<div align="center"> <img src="pics/7e873b60-44dc-4911-b080-defd5b8f0b49.png"/> </div><br>
## 启动速度
@ -76,7 +76,7 @@ Docker 轻量级的特点使得它很适合用于部署、维护、组合微服
构建容器时通过在镜像的基础上添加一个可写层writable layer用来保存着容器运行过程中的修改。
<div align="center"> <img src="../pics//docker-filesystems-busyboxrw.png"/> </div><br>
<div align="center"> <img src="pics/docker-filesystems-busyboxrw.png"/> </div><br>
# 参考资料

View File

@ -34,20 +34,20 @@ Github 就是一个中心服务器。
# 工作流
<div align="center"> <img src="../pics//a1198642-9159-4d88-8aec-c3b04e7a2563.jpg"/> </div><br>
<div align="center"> <img src="pics/a1198642-9159-4d88-8aec-c3b04e7a2563.jpg"/> </div><br>
新建一个仓库之后,当前目录就成为了工作区,工作区下有一个隐藏目录 .git它属于 Git 的版本库。
Git 版本库有一个称为 stage 的暂存区,还有自动创建的 master 分支以及指向分支的 HEAD 指针。
<div align="center"> <img src="../pics//46f66e88-e65a-4ad0-a060-3c63fe22947c.png"/> </div><br>
<div align="center"> <img src="pics/46f66e88-e65a-4ad0-a060-3c63fe22947c.png"/> </div><br>
- git add files 把文件的修改添加到暂存区
- git commit 把暂存区的修改提交到当前分支,提交之后暂存区就被清空了
- git reset -- files 使用当前分支上的修改覆盖暂存区,用来撤销最后一次 git add files
- git checkout -- files 使用暂存区的修改覆盖工作目录,用来撤销本地修改
<div align="center"> <img src="../pics//17976404-95f5-480e-9cb4-250e6aa1d55f.png"/> </div><br>
<div align="center"> <img src="pics/17976404-95f5-480e-9cb4-250e6aa1d55f.png"/> </div><br>
可以跳过暂存区域直接从分支中取出修改,或者直接提交修改到分支中。
@ -58,25 +58,25 @@ Git 版本库有一个称为 stage 的暂存区,还有自动创建的 master
使用指针将每个提交连接成一条时间线HEAD 指针指向当前分支指针。
<div align="center"> <img src="../pics//fb546e12-e1fb-4b72-a1fb-8a7f5000dce6.jpg"/> </div><br>
<div align="center"> <img src="pics/fb546e12-e1fb-4b72-a1fb-8a7f5000dce6.jpg"/> </div><br>
新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。
<div align="center"> <img src="../pics//bc775758-89ab-4805-9f9c-78b8739cf780.jpg"/> </div><br>
<div align="center"> <img src="pics/bc775758-89ab-4805-9f9c-78b8739cf780.jpg"/> </div><br>
每次提交只会让当前分支指针向前移动,而其它分支指针不会移动。
<div align="center"> <img src="../pics//5292faa6-0141-4638-bf0f-bb95b081dcba.jpg"/> </div><br>
<div align="center"> <img src="pics/5292faa6-0141-4638-bf0f-bb95b081dcba.jpg"/> </div><br>
合并分支也只需要改变指针即可。
<div align="center"> <img src="../pics//1164a71f-413d-494a-9cc8-679fb6a2613d.jpg"/> </div><br>
<div align="center"> <img src="pics/1164a71f-413d-494a-9cc8-679fb6a2613d.jpg"/> </div><br>
# 冲突
当两个分支都对同一个文件的同一行进行了修改,在分支合并时就会产生冲突。
<div align="center"> <img src="../pics//58e57a21-6b6b-40b6-af85-956dd4e0f55a.jpg"/> </div><br>
<div align="center"> <img src="pics/58e57a21-6b6b-40b6-af85-956dd4e0f55a.jpg"/> </div><br>
Git 会使用 <<<<<<< ======= >>>>>>> 标记出不同分支的内容,只需要把不同分支中冲突部分修改成一样就能解决冲突。
@ -98,7 +98,7 @@ Creating a new branch is quick AND simple.
$ git merge --no-ff -m "merge with no-ff" dev
```
<div align="center"> <img src="../pics//dd78a1fe-1ff3-4bcf-a56f-8c003995beb6.jpg"/> </div><br>
<div align="center"> <img src="pics/dd78a1fe-1ff3-4bcf-a56f-8c003995beb6.jpg"/> </div><br>
# 分支管理策略
@ -106,7 +106,7 @@ master 分支应该是非常稳定的,只用来发布新版本;
日常开发在开发分支 dev 上进行。
<div align="center"> <img src="../pics//245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg"/> </div><br>
<div align="center"> <img src="pics/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg"/> </div><br>
# 储藏Stashing
@ -146,7 +146,7 @@ $ ssh-keygen -t rsa -C "youremail@example.com"
# Git 命令一览
<div align="center"> <img src="../pics//7a29acce-f243-4914-9f00-f2988c528412.jpg"/> </div><br>
<div align="center"> <img src="pics/7a29acce-f243-4914-9f00-f2988c528412.jpg"/> </div><br>
比较详细的地址http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf

View File

@ -66,17 +66,17 @@ URI 包含 URL 和 URN目前 WEB 只有 URL 比较流行,所以见到的基
- URLUniform Resource Locator统一资源定位符
- URNUniform Resource Name统一资源名称
<div align="center"> <img src="../pics//urlnuri.jpg" width="600"/> </div><br>
<div align="center"> <img src="pics/urlnuri.jpg" width="600"/> </div><br>
## 请求和响应报文
### 1. 请求报文
<div align="center"> <img src="../pics//HTTP_RequestMessageExample.png" width=""/> </div><br>
<div align="center"> <img src="pics/HTTP_RequestMessageExample.png" width=""/> </div><br>
### 2. 响应报文
<div align="center"> <img src="../pics//HTTP_ResponseMessageExample.png" width=""/> </div><br>
<div align="center"> <img src="pics/HTTP_ResponseMessageExample.png" width=""/> </div><br>
# 二、HTTP 方法
@ -163,7 +163,7 @@ DELETE /file.html HTTP/1.1
CONNECT www.example.com:443 HTTP/1.1
```
<div align="center"> <img src="../pics//dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br>
## TRACE
@ -305,7 +305,7 @@ CONNECT www.example.com:443 HTTP/1.1
## 连接管理
<div align="center"> <img src="../pics//HTTP1_x_Connections.png" width="800"/> </div><br>
<div align="center"> <img src="pics/HTTP1_x_Connections.png" width="800"/> </div><br>
### 1. 短连接与长连接
@ -634,11 +634,11 @@ HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,
- 用户察觉得到正向代理的存在。
<div align="center"> <img src="../pics//a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br>
<div align="center"> <img src="pics/a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br>
- 而反向代理一般位于内部网络中,用户察觉不到。
<div align="center"> <img src="../pics//2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br>
<div align="center"> <img src="pics/2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br>
### 2. 网关
@ -660,7 +660,7 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer
通过使用 SSLHTTPs 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
<div align="center"> <img src="../pics//ssl-offloading.jpg" width="700"/> </div><br>
<div align="center"> <img src="pics/ssl-offloading.jpg" width="700"/> </div><br>
## 加密
@ -671,7 +671,7 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer
- 优点:运算速度快;
- 缺点:无法安全地将密钥传输给通信方。
<div align="center"> <img src="../pics//7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
<div align="center"> <img src="pics/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
### 2.非对称密钥加密
@ -684,13 +684,13 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer
- 优点:可以更安全地将公开密钥传输给通信发送方;
- 缺点:运算速度慢。
<div align="center"> <img src="../pics//39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
<div align="center"> <img src="pics/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
### 3. HTTPs 采用的加密方式
HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥)
<div align="center"> <img src="../pics//How-HTTPS-Works.png" width="600"/> </div><br>
<div align="center"> <img src="pics/How-HTTPS-Works.png" width="600"/> </div><br>
## 认证
@ -704,7 +704,7 @@ HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对
通信开始时,客户端需要使用服务器的公开密钥将自己的私有密钥传输给服务器,之后再进行对称密钥加密。
<div align="center"> <img src="../pics//2017-06-11-ca.png" width=""/> </div><br>
<div align="center"> <img src="pics/2017-06-11-ca.png" width=""/> </div><br>
## 完整性保护
@ -732,7 +732,7 @@ HTTP/1.x 实现简单是以牺牲性能为代价的:
HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。
<div align="center"> <img src="../pics//86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br>
<div align="center"> <img src="pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br>
在通信过程中,只会有一个 TCP 连接存在它承载了任意数量的双向数据流Stream
@ -740,13 +740,13 @@ HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式
- 消息Message是与逻辑请求或响应对应的完整的一系列帧。
- 帧Frame是最小的通信单位来自不同数据流的帧可以交错发送然后再根据每个帧头的数据流标识符重新组装。
<div align="center"> <img src="../pics//af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br>
<div align="center"> <img src="pics/af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br>
## 服务端推送
HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
<div align="center"> <img src="../pics//e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br>
<div align="center"> <img src="pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br>
## 首部压缩
@ -756,7 +756,7 @@ HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见
不仅如此HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。
<div align="center"> <img src="../pics//_u4E0B_u8F7D.png" width="600"/> </div><br>
<div align="center"> <img src="pics/_u4E0B_u8F7D.png" width="600"/> </div><br>
# 八、HTTP/1.1 新特性

View File

@ -97,7 +97,7 @@ Java I/O 使用了装饰者模式来实现。以 InputStream 为例,
- FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作;
- FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能。例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。
<div align="center"> <img src="../pics//DP-Decorator-java.io.png" width="500"/> </div><br>
<div align="center"> <img src="pics/DP-Decorator-java.io.png" width="500"/> </div><br>
实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。
@ -277,7 +277,7 @@ public static void main(String[] args) throws IOException {
- Socket客户端类
- 服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。
<div align="center"> <img src="../pics//ClienteServidorSockets1521731145260.jpg"/> </div><br>
<div align="center"> <img src="pics/ClienteServidorSockets1521731145260.jpg"/> </div><br>
## Datagram
@ -339,23 +339,23 @@ I/O 包和 NIO 已经很好地集成了java.io.\* 已经以 NIO 为基础重
① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。
<div align="center"> <img src="../pics//1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br>
<div align="center"> <img src="pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br>
② 从输入通道中读取 5 个字节数据写入缓冲区中,此时 position 为 5limit 保持不变。
<div align="center"> <img src="../pics//80804f52-8815-4096-b506-48eef3eed5c6.png"/> </div><br>
<div align="center"> <img src="pics/80804f52-8815-4096-b506-48eef3eed5c6.png"/> </div><br>
③ 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position并将 position 设置为 0。
<div align="center"> <img src="../pics//952e06bd-5a65-4cab-82e4-dd1536462f38.png"/> </div><br>
<div align="center"> <img src="pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png"/> </div><br>
④ 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。
<div align="center"> <img src="../pics//b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png"/> </div><br>
<div align="center"> <img src="pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png"/> </div><br>
⑤ 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。
<div align="center"> <img src="../pics//67bf5487-c45d-49b6-b9c0-a058d8c68902.png"/> </div><br>
<div align="center"> <img src="pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png"/> </div><br>
## 文件 NIO 实例
@ -413,7 +413,7 @@ NIO 实现了 IO 多路复用中的 Reactor 模型,一个线程 Thread 使用
应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞也没有意义。
<div align="center"> <img src="../pics//4d930e22-f493-49ae-8dff-ea21cd6895dc.png"/> </div><br>
<div align="center"> <img src="pics/4d930e22-f493-49ae-8dff-ea21cd6895dc.png"/> </div><br>
### 1. 创建选择器

View File

@ -167,7 +167,7 @@ public final class String
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
<div align="center"> <img src="../pics//f76067a5-7d5f-4135-9549-8199c77d8f1c.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/f76067a5-7d5f-4135-9549-8199c77d8f1c.jpg" width=""/> </div><br>
**3. 安全性**
@ -1236,7 +1236,7 @@ Throwable 可以用来表示任何可以作为异常抛出的类,分为两种
- **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
- **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception此时程序崩溃并且无法恢复。
<div align="center"> <img src="../pics//PPjwP.png" width="600"/> </div><br>
<div align="center"> <img src="pics/PPjwP.png" width="600"/> </div><br>
- [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
- [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)

View File

@ -25,7 +25,7 @@
## Collection
<div align="center"> <img src="../pics//VP6n3i8W48Ptde8NQ9_0eSR5eOD6uqx.png"/> </div><br>
<div align="center"> <img src="pics/VP6n3i8W48Ptde8NQ9_0eSR5eOD6uqx.png"/> </div><br>
### 1. Set
@ -51,7 +51,7 @@
## Map
<div align="center"> <img src="../pics//SoWkIImgAStDuUBAp2j9BKfBJ4vLy4q.png"/> </div><br>
<div align="center"> <img src="pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy4q.png"/> </div><br>
- TreeMap基于红黑树实现。
@ -66,7 +66,7 @@
## 迭代器模式
<div align="center"> <img src="../pics//SoWkIImgAStDuUBAp2j9BKfBJ4vLy0G.png"/> </div><br>
<div align="center"> <img src="pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy0G.png"/> </div><br>
Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。
@ -387,7 +387,7 @@ transient Node<E> first;
transient Node<E> last;
```
<div align="center"> <img src="../pics//49495c95-52e5-4c9a-b27b-92cf235ff5ec.png" width="500"/> </div><br>
<div align="center"> <img src="pics/49495c95-52e5-4c9a-b27b-92cf235ff5ec.png" width="500"/> </div><br>
### 2. 与 ArrayList 的比较
@ -409,7 +409,7 @@ transient Entry[] table;
Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值相同的 Entry。
<div align="center"> <img src="../pics//8fe838e3-ef77-4f63-bf45-417b6bc5c6bb.png" width="600"/> </div><br>
<div align="center"> <img src="pics/8fe838e3-ef77-4f63-bf45-417b6bc5c6bb.png" width="600"/> </div><br>
```java
static class Entry<K,V> implements Map.Entry<K,V> {
@ -485,7 +485,7 @@ map.put("K3", "V3");
- 计算键值对所在的桶;
- 在链表上顺序查找,时间复杂度显然和链表的长度成正比。
<div align="center"> <img src="../pics//49d6de7b-0d0d-425c-9e49-a1559dc23b10.png" width="600"/> </div><br>
<div align="center"> <img src="pics/49d6de7b-0d0d-425c-9e49-a1559dc23b10.png" width="600"/> </div><br>
### 3. put 操作
@ -821,7 +821,7 @@ final Segment<K,V>[] segments;
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
```
<div align="center"> <img src="../pics//3fdfc89d-719e-4d93-b518-29fa612b3b18.png"/> </div><br>
<div align="center"> <img src="pics/3fdfc89d-719e-4d93-b518-29fa612b3b18.png"/> </div><br>
### 2. size 操作

View File

@ -61,7 +61,7 @@
# 一、线程状态转换
<div align="center"> <img src="../pics//ace830df-9919-48ca-91b5-60b193f593d2.png" width=""/> </div><br>
<div align="center"> <img src="pics/ace830df-9919-48ca-91b5-60b193f593d2.png" width=""/> </div><br>
## 新建New
@ -736,7 +736,7 @@ java.util.concurrentJ.U.C大大提高了并发性能AQS 被认为是 J.
维护了一个计数器 cnt每次调用 countDown() 方法会让计数器的值减 1减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。
<div align="center"> <img src="../pics//CountdownLatch.png" width=""/> </div><br>
<div align="center"> <img src="pics/CountdownLatch.png" width=""/> </div><br>
```java
public class CountdownLatchExample {
@ -785,7 +785,7 @@ public CyclicBarrier(int parties) {
}
```
<div align="center"> <img src="../pics//CyclicBarrier.png" width=""/> </div><br>
<div align="center"> <img src="pics/CyclicBarrier.png" width=""/> </div><br>
```java
public class CyclicBarrierExample {
@ -818,7 +818,7 @@ before..before..before..before..before..before..before..before..before..before..
Semaphore 类似于操作系统中的信号量,可以控制对互斥资源的访问线程数。
<div align="center"> <img src="../pics//Semaphore.png" width=""/> </div><br>
<div align="center"> <img src="pics/Semaphore.png" width=""/> </div><br>
以下代码模拟了对某个服务的并发请求,每次只能有 3 个客户端同时访问,请求总数为 10。
@ -1024,7 +1024,7 @@ public class ForkJoinPool extends AbstractExecutorService
ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务避免和队列所属线程发生竞争。例如下图中Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。
<div align="center"> <img src="../pics//15b45dc6-27aa-4519-9194-f4acfa2b077f.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/15b45dc6-27aa-4519-9194-f4acfa2b077f.jpg" width=""/> </div><br>
# 九、线程不安全示例
@ -1079,19 +1079,19 @@ Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,
加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。
<div align="center"> <img src="../pics//68778c1b-15ab-4826-99c0-3b4fd38cb9e9.png" width=""/> </div><br>
<div align="center"> <img src="pics/68778c1b-15ab-4826-99c0-3b4fd38cb9e9.png" width=""/> </div><br>
所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。
线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
<div align="center"> <img src="../pics//47358f87-bc4c-496f-9a90-8d696de94cee.png" width=""/> </div><br>
<div align="center"> <img src="pics/47358f87-bc4c-496f-9a90-8d696de94cee.png" width=""/> </div><br>
## 内存间交互操作
Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。
<div align="center"> <img src="../pics//536c6dfd-305a-4b95-b12c-28ca5e8aa043.png" width=""/> </div><br>
<div align="center"> <img src="pics/536c6dfd-305a-4b95-b12c-28ca5e8aa043.png" width=""/> </div><br>
- read把一个变量的值从主内存传输到工作内存中
- load在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
@ -1114,11 +1114,11 @@ Java 内存模型保证了 read、load、use、assign、store、write、lock 和
下图演示了两个线程同时对 cnt 进行操作load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。
<div align="center"> <img src="../pics//ef8eab00-1d5e-4d99-a7c2-d6d68ea7fe92.png" width=""/> </div><br>
<div align="center"> <img src="pics/ef8eab00-1d5e-4d99-a7c2-d6d68ea7fe92.png" width=""/> </div><br>
AtomicInteger 能保证多个线程修改的原子性。
<div align="center"> <img src="../pics//952afa9a-458b-44ce-bba9-463e60162945.png" width=""/> </div><br>
<div align="center"> <img src="pics/952afa9a-458b-44ce-bba9-463e60162945.png" width=""/> </div><br>
使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现:
@ -1226,7 +1226,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
在一个线程内,在程序前面的操作先行发生于后面的操作。
<div align="center"> <img src="../pics//single-thread-rule.png" width=""/> </div><br>
<div align="center"> <img src="pics/single-thread-rule.png" width=""/> </div><br>
### 2. 管程锁定规则
@ -1234,7 +1234,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。
<div align="center"> <img src="../pics//monitor-lock-rule.png" width=""/> </div><br>
<div align="center"> <img src="pics/monitor-lock-rule.png" width=""/> </div><br>
### 3. volatile 变量规则
@ -1242,7 +1242,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。
<div align="center"> <img src="../pics//volatile-variable-rule.png" width=""/> </div><br>
<div align="center"> <img src="pics/volatile-variable-rule.png" width=""/> </div><br>
### 4. 线程启动规则
@ -1250,7 +1250,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。
<div align="center"> <img src="../pics//thread-start-rule.png" width=""/> </div><br>
<div align="center"> <img src="pics/thread-start-rule.png" width=""/> </div><br>
### 5. 线程加入规则
@ -1258,7 +1258,7 @@ Thread 对象的 start() 方法调用先行发生于此线程的每一个动作
Thread 对象的结束先行发生于 join() 方法返回。
<div align="center"> <img src="../pics//thread-join-rule.png" width=""/> </div><br>
<div align="center"> <img src="pics/thread-join-rule.png" width=""/> </div><br>
### 6. 线程中断规则
@ -1476,7 +1476,7 @@ public class ThreadLocalExample1 {
它所对应的底层结构图为:
<div align="center"> <img src="../pics//3646544a-cb57-451d-9e03-d3c4f5e4434a.png" width=""/> </div><br>
<div align="center"> <img src="pics/3646544a-cb57-451d-9e03-d3c4f5e4434a.png" width=""/> </div><br>
每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。
@ -1579,17 +1579,17 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
以下是 HotSpot 虚拟机对象头的内存布局,这些数据被称为 Mark Word。其中 tag bits 对应了五个状态,这些状态在右侧的 state 表格中给出。除了 marked for gc 状态,其它四个状态已经在前面介绍过了。
<div align="center"> <img src="../pics//bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br>
<div align="center"> <img src="pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br>
下图左侧是一个线程的虚拟机栈,其中有一部分称为 Lock Record 的区域,这是在轻量级锁运行过程创建的,用于存放锁对象的 Mark Word。而右侧就是一个锁对象包含了 Mark Word 和其它信息。
<div align="center"> <img src="../pics//051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/> </div><br>
<div align="center"> <img src="pics/051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/> </div><br>
轻量级锁是相对于传统的重量级锁而言,它使用 CAS 操作来避免重量级锁使用互斥量的开销。对于绝大部分的锁,在整个同步周期内都是不存在竞争的,因此也就不需要都使用互斥量进行同步,可以先采用 CAS 操作进行同步,如果 CAS 失败了再改用互斥量进行同步。
当尝试获取一个锁对象时,如果锁对象标记为 0 01说明锁对象的锁未锁定unlocked状态。此时虚拟机在当前线程的虚拟机栈中创建 Lock Record然后使用 CAS 操作将对象的 Mark Word 更新为 Lock Record 指针。如果 CAS 操作成功了,那么线程就获取了该对象上的锁,并且对象的 Mark Word 的锁标记变为 00表示该对象处于轻量级锁状态。
<div align="center"> <img src="../pics//baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/> </div><br>
<div align="center"> <img src="pics/baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/> </div><br>
如果 CAS 操作失败了,虚拟机首先会检查对象的 Mark Word 是否指向当前线程的虚拟机栈,如果是的话说明当前线程已经拥有了这个锁对象,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁。
@ -1601,7 +1601,7 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
当有另外一个线程去尝试获取这个锁对象时偏向状态就宣告结束此时撤销偏向Revoke Bias后恢复到未锁定状态或者轻量级锁状态。
<div align="center"> <img src="../pics//390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/> </div><br>
<div align="center"> <img src="pics/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/> </div><br>
# 十三、多线程开发良好的实践

View File

@ -30,7 +30,7 @@
# 一、运行时数据区域
<div align="center"> <img src="../pics//85370d54-40d1-4912-bcbe-37a2481c861d.png" width="450"/> </div><br>
<div align="center"> <img src="pics/85370d54-40d1-4912-bcbe-37a2481c861d.png" width="450"/> </div><br>
## 程序计数器
@ -40,7 +40,7 @@
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
<div align="center"> <img src="../pics//28ab96b4-82ea-4d99-99fb-b320f60d0a58.png" width="500"/> </div><br>
<div align="center"> <img src="pics/28ab96b4-82ea-4d99-99fb-b320f60d0a58.png" width="500"/> </div><br>
可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小:
@ -59,7 +59,7 @@ java -Xss512M HackTheJava
本地方法一般是用其它语言C、C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
<div align="center"> <img src="../pics//JNI-Java-Native-Interface.jpg" width="350"/> </div><br>
<div align="center"> <img src="pics/JNI-Java-Native-Interface.jpg" width="350"/> </div><br>
## 堆
@ -143,7 +143,7 @@ Java 虚拟机使用该算法来判断对象是否可被回收,在 Java 中 GC
- 方法区中类静态属性引用的对象
- 方法区中的常量引用的对象
<div align="center"> <img src="../pics//0635cbe8.png" width=""/> </div><br>
<div align="center"> <img src="pics/0635cbe8.png" width=""/> </div><br>
### 3. 方法区的回收
@ -225,7 +225,7 @@ obj = null;
### 1. 标记 - 清除
<div align="center"> <img src="../pics//a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg" width=""/> </div><br>
标记要回收的对象,然后清除。
@ -236,13 +236,13 @@ obj = null;
### 2. 标记 - 整理
<div align="center"> <img src="../pics//902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg" width=""/> </div><br>
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
### 3. 复制
<div align="center"> <img src="../pics//e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg" width=""/> </div><br>
将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
@ -263,7 +263,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 的大小比例默认为 8:1保证了
## 垃圾收集器
<div align="center"> <img src="../pics//c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div><br>
以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。
@ -272,7 +272,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 的大小比例默认为 8:1保证了
### 1. Serial 收集器
<div align="center"> <img src="../pics//22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div><br>
Serial 翻译为串行,也就是说它以串行的方式执行。
@ -284,7 +284,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 2. ParNew 收集器
<div align="center"> <img src="../pics//81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div><br>
它是 Serial 收集器的多线程版本。
@ -306,7 +306,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 4. Serial Old 收集器
<div align="center"> <img src="../pics//08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div><br>
是 Serial 收集器的老年代版本,也是给 Client 模式下的虚拟机使用。如果用在 Server 模式下,它有两大用途:
@ -315,7 +315,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 5. Parallel Old 收集器
<div align="center"> <img src="../pics//278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div><br>
是 Parallel Scavenge 收集器的老年代版本。
@ -323,7 +323,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 6. CMS 收集器
<div align="center"> <img src="../pics//62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div><br>
CMSConcurrent Mark SweepMark Sweep 指的是标记 - 清除算法。
@ -348,17 +348,17 @@ G1Garbage-First它是一款面向服务端应用的垃圾收集器
堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。
<div align="center"> <img src="../pics//4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/> </div><br>
<div align="center"> <img src="pics/4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/> </div><br>
G1 把堆划分成多个大小相等的独立区域Region新生代和老年代不再物理隔离。
<div align="center"> <img src="../pics//9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/> </div><br>
<div align="center"> <img src="pics/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/> </div><br>
通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。
每个 Region 都有一个 Remembered Set用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set在做可达性分析的时候就可以避免全堆扫描。
<div align="center"> <img src="../pics//f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/> </div><br>
如果不计算维护 Remembered Set 的操作G1 收集器的运作大致可划分为以下几个步骤:
@ -446,7 +446,7 @@ G1 把堆划分成多个大小相等的独立区域Region新生代和
## 类的生命周期
<div align="center"> <img src="../pics//32b8374a-e822-4720-af0b-c0f485095ea2.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/32b8374a-e822-4720-af0b-c0f485095ea2.jpg" width=""/> </div><br>
包括以下 7 个阶段:
@ -622,7 +622,7 @@ System.out.println(ConstClass.HELLOWORLD);
下图展示的类加载器之间的层次关系称为类加载器的双亲委派模型Parents Delegation Model。该模型要求除了顶层的启动类加载器外其余的类加载器都应有自己的父类加载器。这里类加载器之间的父子关系一般通过组合Composition关系来实现而不是通过继承Inheritance的关系实现。
<div align="center"> <img src="../pics//class_loader_hierarchy.png" width="600"/> </div><br>
<div align="center"> <img src="pics/class_loader_hierarchy.png" width="600"/> </div><br>
### 1. 工作过程

View File

@ -463,7 +463,7 @@ public String frequencySort(String s) {
它其实是三向切分快速排序的一种变种,在三向切分快速排序中,每次切分都将数组分成三个区间:小于切分元素、等于切分元素、大于切分元素,而该算法是将数组分成三个区间:等于红色、等于白色、等于蓝色。
<div align="center"> <img src="../pics//3b49dd67-2c40-4b81-8ad2-7bbb1fe2fcbd.png"/> </div><br>
<div align="center"> <img src="pics/3b49dd67-2c40-4b81-8ad2-7bbb1fe2fcbd.png"/> </div><br>
**按颜色进行排序**
@ -1178,7 +1178,7 @@ public List<Integer> diffWaysToCompute(String input) {
### BFS
<div align="center"> <img src="../pics//4ff355cf-9a7f-4468-af43-e5b02038facc.jpg"/> </div><br>
<div align="center"> <img src="pics/4ff355cf-9a7f-4468-af43-e5b02038facc.jpg"/> </div><br>
广度优先搜索一层一层地进行遍历,每层遍历都以上一层遍历的结果作为起点,遍历一个距离能访问到的所有节点。需要注意的是,遍历过的节点不能再次被遍历。
@ -1407,7 +1407,7 @@ private int getShortestPath(List<Integer>[] graphic, int start, int end) {
### DFS
<div align="center"> <img src="../pics//f7f7e3e5-7dd4-4173-9999-576b9e2ac0a2.png"/> </div><br>
<div align="center"> <img src="pics/f7f7e3e5-7dd4-4173-9999-576b9e2ac0a2.png"/> </div><br>
广度优先搜索一层一层遍历,每一层得到的所有新节点,要用队列存储起来以备下一层遍历的时候再遍历。
@ -1718,7 +1718,7 @@ Backtracking回溯属于 DFS。
[17. Letter Combinations of a Phone Number (Medium)](https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/)
<div align="center"> <img src="../pics//a3f34241-bb80-4879-8ec9-dff2d81b514e.jpg"/> </div><br>
<div align="center"> <img src="pics/a3f34241-bb80-4879-8ec9-dff2d81b514e.jpg"/> </div><br>
```html
Input:Digit string "23"
@ -2295,7 +2295,7 @@ private boolean isPalindrome(String s, int begin, int end) {
[37. Sudoku Solver (Hard)](https://leetcode.com/problems/sudoku-solver/description/)
<div align="center"> <img src="../pics//1ca52246-c443-48ae-b1f8-1cafc09ec75c.png"/> </div><br>
<div align="center"> <img src="pics/1ca52246-c443-48ae-b1f8-1cafc09ec75c.png"/> </div><br>
```java
private boolean[][] rowsUsed = new boolean[9][10];
@ -2357,7 +2357,7 @@ private int cubeNum(int i, int j) {
[51. N-Queens (Hard)](https://leetcode.com/problems/n-queens/description/)
<div align="center"> <img src="../pics//1f080e53-4758-406c-bb5f-dbedf89b63ce.jpg"/> </div><br>
<div align="center"> <img src="pics/1f080e53-4758-406c-bb5f-dbedf89b63ce.jpg"/> </div><br>
在 n\*n 的矩阵中摆放 n 个皇后,并且每个皇后不能在同一行,同一列,同一对角线上,求所有的 n 皇后的解。
@ -2365,11 +2365,11 @@ private int cubeNum(int i, int j) {
45 度对角线标记数组的长度为 2 \* n - 1通过下图可以明确 (r, c) 的位置所在的数组下标为 r + c。
<div align="center"> <img src="../pics//85583359-1b45-45f2-9811-4f7bb9a64db7.jpg"/> </div><br>
<div align="center"> <img src="pics/85583359-1b45-45f2-9811-4f7bb9a64db7.jpg"/> </div><br>
135 度对角线标记数组的长度也是 2 \* n - 1(r, c) 的位置所在的数组下标为 n - 1 - (r - c)。
<div align="center"> <img src="../pics//9e80f75a-b12b-4344-80c8-1f9ccc2d5246.jpg"/> </div><br>
<div align="center"> <img src="pics/9e80f75a-b12b-4344-80c8-1f9ccc2d5246.jpg"/> </div><br>
```java
private List<List<String>> solutions;
@ -2571,7 +2571,7 @@ public int minPathSum(int[][] grid) {
题目描述:统计从矩阵左上角到右下角的路径总数,每次只能向右或者向下移动。
<div align="center"> <img src="../pics//7c98e1b6-c446-4cde-8513-5c11b9f52aea.jpg"/> </div><br>
<div align="center"> <img src="pics/7c98e1b6-c446-4cde-8513-5c11b9f52aea.jpg"/> </div><br>
```java
public int uniquePaths(int m, int n) {
@ -3302,7 +3302,7 @@ public int combinationSum4(int[] nums, int target) {
题目描述:交易之后需要有一天的冷却时间。
<div align="center"> <img src="../pics//a3da4342-078b-43e2-b748-7e71bec50dc4.png"/> </div><br>
<div align="center"> <img src="pics/a3da4342-078b-43e2-b748-7e71bec50dc4.png"/> </div><br>
```java
public int maxProfit(int[] prices) {
@ -3343,7 +3343,7 @@ The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
题目描述:每交易一次,都要支付一定的费用。
<div align="center"> <img src="../pics//61942711-45a0-4e11-bbc9-434e31436f33.png"/> </div><br>
<div align="center"> <img src="pics/61942711-45a0-4e11-bbc9-434e31436f33.png"/> </div><br>
```java
public int maxProfit(int[] prices, int fee) {
@ -5299,7 +5299,7 @@ private void inOrder(TreeNode node, List<Integer> nums) {
### Trie
<div align="center"> <img src="../pics//5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg"/> </div><br>
<div align="center"> <img src="pics/5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg"/> </div><br>
Trie又称前缀树或字典树用于判断字符串是否存在或者是否具有某种字符串前缀。

View File

@ -157,7 +157,7 @@ Linux 发行版是 Linux 内核及各种应用软件的集成版本。
- 编辑模式Insert mode按下 "i" 等按键之后进入,可以对文本进行编辑;
- 指令列模式Bottom-line mode按下 ":" 按键之后进入,用于保存退出等操作。
<div align="center"> <img src="../pics//5942debd-fc00-477a-b390-7c5692cc8070.jpg" width="400"/> </div><br>
<div align="center"> <img src="pics/5942debd-fc00-477a-b390-7c5692cc8070.jpg" width="400"/> </div><br>
在指令列模式下,有以下命令用于离开或者保存文件。
@ -191,25 +191,25 @@ GNU 计划,译为革奴计划,它的目标是创建一套完全自由的操
IDEATA全称 Advanced Technology Attachment接口速度最大为 133MB/s因为并口线的抗干扰性太差且排线占用空间较大不利电脑内部散热已逐渐被 SATA 所取代。
<div align="center"> <img src="../pics//924914c0-660c-4e4a-bbc0-1df1146e7516.jpg" width="400"/> </div><br>
<div align="center"> <img src="pics/924914c0-660c-4e4a-bbc0-1df1146e7516.jpg" width="400"/> </div><br>
### 2. SATA
SATA 全称 Serial ATA也就是使用串口的 ATA 接口,抗干扰性强,且对数据线的长度要求比 ATA 低很多支持热插拔等功能。SATA-II 的接口速度为 300MiB/s而新的 SATA-III 标准可达到 600MiB/s 的传输速度。SATA 的数据线也比 ATA 的细得多,有利于机箱内的空气流通,整理线材也比较方便。
<div align="center"> <img src="../pics//f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg" width=""/> </div><br>
### 3. SCSI
SCSI 全称是 Small Computer System Interface小型机系统接口经历多代的发展从早期的 SCSI-II 到目前的 Ultra320 SCSI 以及 Fiber-Channel光纤通道接口型式也多种多样。SCSI 硬盘广为工作站级个人电脑以及服务器所使用,因此会使用较为先进的技术,如碟片转速 15000rpm 的高转速,且传输时 CPU 占用率较低,但是单价也比相同容量的 ATA 及 SATA 硬盘更加昂贵。
<div align="center"> <img src="../pics//f0574025-c514-49f5-a591-6d6a71f271f7.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/f0574025-c514-49f5-a591-6d6a71f271f7.jpg" width=""/> </div><br>
### 4. SAS
SASSerial Attached SCSI是新一代的 SCSI 技术,和 SATA 硬盘相同,都是采取序列式技术以获得更高的传输速度,可达到 6Gb/s。此外也透过缩小连接线改善系统内部空间等。
<div align="center"> <img src="../pics//6729baa0-57d7-4817-b3aa-518cbccf824c.jpg" width=""/> </div><br>
<div align="center"> <img src="pics/6729baa0-57d7-4817-b3aa-518cbccf824c.jpg" width=""/> </div><br>
## 磁盘的文件名
@ -244,7 +244,7 @@ GPT 没有扩展分区概念,都是主分区,每个 LAB 可以分 4 个分
MBR 不支持 2.2 TB 以上的硬盘GPT 则最多支持到 2<sup>33</sup> TB = 8 ZB。
<div align="center"> <img src="../pics//GUID_Partition_Table_Scheme.svg.png" width="400"/> </div><br>
<div align="center"> <img src="pics/GUID_Partition_Table_Scheme.svg.png" width="400"/> </div><br>
## 开机检测程序
@ -252,7 +252,7 @@ MBR 不支持 2.2 TB 以上的硬盘GPT 则最多支持到 2<sup>33</sup> TB
BIOSBasic Input/Output System基本输入输出系统它是一个固件嵌入在硬件中的软件BIOS 程序存放在断电后内容不会丢失的只读内存中。
<div align="center"> <img src="../pics//50831a6f-2777-46ea-a571-29f23c85cc21.jpg"/> </div><br>
<div align="center"> <img src="pics/50831a6f-2777-46ea-a571-29f23c85cc21.jpg"/> </div><br>
BIOS 是开机的时候计算机执行的第一个程序这个程序知道可以开机的磁盘并读取磁盘第一个扇区的主要开机记录MBR由主要开机记录MBR执行其中的开机管理程序这个开机管理程序会加载操作系统的核心文件。
@ -260,7 +260,7 @@ BIOS 是开机的时候计算机执行的第一个程序,这个程序知道可
下图中第一扇区的主要开机记录MBR中的开机管理程序提供了两个选单M1、M2M1 指向了 Windows 操作系统,而 M2 指向其它分区的启动扇区,里面包含了另外一个开机管理程序,提供了一个指向 Linux 的选单。
<div align="center"> <img src="../pics//f900f266-a323-42b2-bc43-218fdb8811a8.jpg" width="600"/> </div><br>
<div align="center"> <img src="pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg" width="600"/> </div><br>
安装多重引导,最好先安装 Windows 再安装 Linux。因为安装 Windows 时会覆盖掉主要开机记录MBR而 Linux 可以选择将开机管理程序安装在主要开机记录MBR或者其它分区的启动扇区并且可以设置开机管理程序的选单。
@ -286,17 +286,17 @@ BIOS 不可以读取 GPT 分区表,而 UEFI 可以。
- superblock记录文件系统的整体信息包括 inode 和 block 的总量、使用量、剩余量,以及文件系统的格式与相关信息等;
- block bitmap记录 block 是否被使用的位域。
<div align="center"> <img src="../pics//BSD_disk.png" width="800"/> </div><br>
<div align="center"> <img src="pics/BSD_disk.png" width="800"/> </div><br>
## 文件读取
对于 Ext2 文件系统,当要读取一个文件的内容时,先在 inode 中去查找文件内容所在的所有 block然后把所有 block 的内容读出来。
<div align="center"> <img src="../pics//83185315-793a-453a-a927-5e8d92b5c0ef.jpg"/> </div><br>
<div align="center"> <img src="pics/83185315-793a-453a-a927-5e8d92b5c0ef.jpg"/> </div><br>
而对于 FAT 文件系统,它没有 inode每个 block 中存储着下一个 block 的编号。
<div align="center"> <img src="../pics//075e1977-7846-4928-96c8-bb5b0268693c.jpg"/> </div><br>
<div align="center"> <img src="pics/075e1977-7846-4928-96c8-bb5b0268693c.jpg"/> </div><br>
## 磁盘碎片
@ -333,7 +333,7 @@ inode 具有以下特点:
inode 中记录了文件内容所在的 block 编号,但是每个 block 非常小,一个大文件随便都需要几十万的 block。而一个 inode 大小有限,无法直接引用这么多 block 编号。因此引入了间接、双间接、三间接引用。间接引用是指,让 inode 记录的引用 block 块记录引用信息。
<div align="center"> <img src="../pics//inode_with_signatures.jpg" width="600"/> </div><br>
<div align="center"> <img src="pics/inode_with_signatures.jpg" width="600"/> </div><br>
## 目录
@ -359,7 +359,7 @@ ext3/ext4 文件系统引入了日志功能,可以利用日志来修复文件
- /usr (unix software resource):所有系统默认软件都会安装到这个目录;
- /var (variable):存放系统或程序运行过程中的数据文件。
<div align="center"> <img src="../pics//linux-filesystem.png" width=""/> </div><br>
<div align="center"> <img src="pics/linux-filesystem.png" width=""/> </div><br>
# 五、文件
@ -534,7 +534,7 @@ cp [-adfilprsu] source destination
-f :如果目标文件存在时,先删除目标文件
```
<div align="center"> <img src="../pics//b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg"/> </div><br>
<div align="center"> <img src="pics/b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg"/> </div><br>
### 1. 实体链接
@ -655,7 +655,7 @@ example: find . -name "shadow*"
+4、4 和 -4 的指示的时间范围如下:
<div align="center"> <img src="../pics//658fc5e7-79c0-4247-9445-d69bf194c539.png" width=""/> </div><br>
<div align="center"> <img src="pics/658fc5e7-79c0-4247-9445-d69bf194c539.png" width=""/> </div><br>
**② 与文件拥有者和所属群组有关的选项**
@ -1168,7 +1168,7 @@ dmtsai lines: 5 columns: 9
| Z | zombie (terminated but not reaped by its parent) |
| T | stopped (either by a job control signal or because it is being traced) |
<br>
<div align="center"> <img src="../pics//76a49594323247f21c9b3a69945445ee.png" width=""/> </div><br>
<div align="center"> <img src="pics/76a49594323247f21c9b3a69945445ee.png" width=""/> </div><br>
## SIGCHLD
@ -1181,7 +1181,7 @@ dmtsai lines: 5 columns: 9
在子进程退出时,它的进程描述符不会立即释放,这是为了让父进程得到子进程信息,父进程通过 wait() 和 waitpid() 来获得一个已经退出的子进程的信息。
<div align="center"> <img src="../pics//flow.png" width=""/> </div><br>
<div align="center"> <img src="pics/flow.png" width=""/> </div><br>
## wait()

View File

@ -42,7 +42,7 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 key<sub>i</sub> 和 key<sub>i+1</sub>,且不为 null则该指针指向节点的所有 key 大于等于 key<sub>i</sub> 且小于等于 key<sub>i+1</sub>
<div align="center"> <img src="../pics//061c88c1-572f-424f-b580-9cbce903a3fe.png"/> </div><br>
<div align="center"> <img src="pics/061c88c1-572f-424f-b580-9cbce903a3fe.png"/> </div><br>
### 2. 操作
@ -84,11 +84,11 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
InnoDB 的 B+Tree 索引分为主索引和辅助索引。主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
<div align="center"> <img src="../pics//c28c6fbc-2bc1-47d9-9b2e-cf3d4034f877.jpg"/> </div><br>
<div align="center"> <img src="pics/c28c6fbc-2bc1-47d9-9b2e-cf3d4034f877.jpg"/> </div><br>
辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。
<div align="center"> <img src="../pics//7ab8ca28-2a41-4adf-9502-cc0a21e63b51.jpg"/> </div><br>
<div align="center"> <img src="pics/7ab8ca28-2a41-4adf-9502-cc0a21e63b51.jpg"/> </div><br>
### 2. 哈希索引
@ -350,7 +350,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
当一个表的数据不断增多时Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。
<div align="center"> <img src="../pics//63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg"/> </div><br>
<div align="center"> <img src="pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg"/> </div><br>
## 垂直切分
@ -358,7 +358,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。
<div align="center"> <img src="../pics//e130e5b8-b19a-4f1e-b860-223040525cf6.jpg"/> </div><br>
<div align="center"> <img src="pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg"/> </div><br>
## Sharding 策略
@ -392,7 +392,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
- **I/O 线程** 负责从主服务器上读取二进制日志并写入从服务器的重放日志Replay log中。
- **SQL 线程** :负责读取重放日志并重放其中的 SQL 语句。
<div align="center"> <img src="../pics//master-slave.png"/> </div><br>
<div align="center"> <img src="pics/master-slave.png"/> </div><br>
## 读写分离
@ -406,7 +406,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
<div align="center"> <img src="../pics//master-slave-proxy.png"/> </div><br>
<div align="center"> <img src="pics/master-slave-proxy.png"/> </div><br>
# 参考资料

View File

@ -67,7 +67,7 @@ Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,
## STRING
<div align="center"> <img src="../pics//6019b2db-bc3e-4408-b6d8-96025f4481d6.png" width="400"/> </div><br>
<div align="center"> <img src="pics/6019b2db-bc3e-4408-b6d8-96025f4481d6.png" width="400"/> </div><br>
```html
> set hello world
@ -82,7 +82,7 @@ OK
## LIST
<div align="center"> <img src="../pics//fb327611-7e2b-4f2f-9f5b-38592d408f07.png" width="400"/> </div><br>
<div align="center"> <img src="pics/fb327611-7e2b-4f2f-9f5b-38592d408f07.png" width="400"/> </div><br>
```html
> rpush list-key item
@ -110,7 +110,7 @@ OK
## SET
<div align="center"> <img src="../pics//cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png" width="400"/> </div><br>
<div align="center"> <img src="pics/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png" width="400"/> </div><br>
```html
> sadd set-key item
@ -144,7 +144,7 @@ OK
## HASH
<div align="center"> <img src="../pics//7bd202a7-93d4-4f3a-a878-af68ae25539a.png" width="400"/> </div><br>
<div align="center"> <img src="pics/7bd202a7-93d4-4f3a-a878-af68ae25539a.png" width="400"/> </div><br>
```html
> hset hash-key sub-key1 value1
@ -175,7 +175,7 @@ OK
## ZSET
<div align="center"> <img src="../pics//1202b2d6-9469-4251-bd47-ca6034fb6116.png" width="400"/> </div><br>
<div align="center"> <img src="pics/1202b2d6-9469-4251-bd47-ca6034fb6116.png" width="400"/> </div><br>
```html
> zadd zset-key 728 member1
@ -317,11 +317,11 @@ int dictRehash(dict *d, int n) {
跳跃表是基于多指针有序链表实现的,可以看成多个有序链表。
<div align="center"> <img src="../pics//beba612e-dc5b-4fc2-869d-0b23408ac90a.png"/> </div><br>
<div align="center"> <img src="pics/beba612e-dc5b-4fc2-869d-0b23408ac90a.png"/> </div><br>
在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。下图演示了查找 22 的过程。
<div align="center"> <img src="../pics//0ea37ee2-c224-4c79-b895-e131c6805c40.png"/> </div><br>
<div align="center"> <img src="pics/0ea37ee2-c224-4c79-b895-e131c6805c40.png"/> </div><br>
与红黑树等平衡树相比,跳跃表具有以下优点:
@ -472,7 +472,7 @@ Redis 服务器是一个事件驱动程序。
Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的事件传送给文件事件分派器,分派器会根据套接字产生的事件类型调用相应的事件处理器。
<div align="center"> <img src="../pics//9ea86eb5-000a-4281-b948-7b567bd6f1d8.png"/> </div><br>
<div align="center"> <img src="pics/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png"/> </div><br>
## 时间事件
@ -525,7 +525,7 @@ def main():
从事件处理的角度来看,服务器运行流程如下:
<div align="center"> <img src="../pics//c0a9fa91-da2e-4892-8c9f-80206a6f7047.png" width="400"/> </div><br>
<div align="center"> <img src="pics/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png" width="400"/> </div><br>
# 十一、复制
@ -545,7 +545,7 @@ def main():
随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。
<div align="center"> <img src="../pics//395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png" width="600"/> </div><br>
<div align="center"> <img src="pics/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png" width="600"/> </div><br>
# 十二、Sentinel
@ -580,7 +580,7 @@ Sentinel哨兵可以监听集群中的服务器并在主服务器进入
Redis 没有关系型数据库中的表这一概念来将同种类型的数据存放在一起,而是使用命名空间的方式来实现这一功能。键名的前面部分存储命名空间,后面部分的内容存储 ID通常使用 : 来进行分隔。例如下面的 HASH 的键名为 article:92617其中 article 为命名空间ID 为 92617。
<div align="center"> <img src="../pics//7c54de21-e2ff-402e-bc42-4037de1c1592.png" width="400"/> </div><br>
<div align="center"> <img src="pics/7c54de21-e2ff-402e-bc42-4037de1c1592.png" width="400"/> </div><br>
## 点赞功能
@ -588,13 +588,13 @@ Redis 没有关系型数据库中的表这一概念来将同种类型的数据
为了节约内存,规定一篇文章发布满一周之后,就不能再对它进行投票,而文章的已投票集合也会被删除,可以为文章的已投票集合设置一个一周的过期时间就能实现这个规定。
<div align="center"> <img src="../pics//485fdf34-ccf8-4185-97c6-17374ee719a0.png" width="400"/> </div><br>
<div align="center"> <img src="pics/485fdf34-ccf8-4185-97c6-17374ee719a0.png" width="400"/> </div><br>
## 对文章进行排序
为了按发布时间和点赞数进行排序,可以建立一个文章发布时间的有序集合和一个文章点赞数的有序集合。(下图中的 score 就是这里所说的点赞数;下面所示的有序集合分值并不直接是时间和点赞数,而是根据时间和点赞数间接计算出来的)
<div align="center"> <img src="../pics//f7d170a3-e446-4a64-ac2d-cb95028f81a8.png" width="800"/> </div><br>
<div align="center"> <img src="pics/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png" width="800"/> </div><br>
# 参考资料

View File

@ -46,7 +46,7 @@ Unix 有五种 I/O 模型:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
```
<div align="center"> <img src="../pics//1492928416812_4.png"/> </div><br>
<div align="center"> <img src="pics/1492928416812_4.png"/> </div><br>
## 非阻塞式 I/O
@ -54,7 +54,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率是比较低的。
<div align="center"> <img src="../pics//1492929000361_5.png"/> </div><br>
<div align="center"> <img src="pics/1492929000361_5.png"/> </div><br>
## I/O 复用
@ -64,7 +64,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接那么就需要创建相同数量的线程。相比于多进程和多线程技术I/O 复用不需要进程线程创建和切换的开销,系统开销更小。
<div align="center"> <img src="../pics//1492929444818_6.png"/> </div><br>
<div align="center"> <img src="pics/1492929444818_6.png"/> </div><br>
## 信号驱动 I/O
@ -72,7 +72,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。
<div align="center"> <img src="../pics//1492929553651_7.png"/> </div><br>
<div align="center"> <img src="pics/1492929553651_7.png"/> </div><br>
## 异步 I/O
@ -80,7 +80,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。
<div align="center"> <img src="../pics//1492930243286_8.png"/> </div><br>
<div align="center"> <img src="pics/1492930243286_8.png"/> </div><br>
## 五大 I/O 模型比较
@ -91,7 +91,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
非阻塞式 I/O 、信号驱动 I/O 和异步 I/O 在第一阶段不会阻塞。
<div align="center"> <img src="../pics//1492928105791_3.png"/> </div><br>
<div align="center"> <img src="pics/1492928105791_3.png"/> </div><br>
# 二、I/O 复用

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/notes/pics/10.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

BIN
docs/notes/pics/11.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Some files were not shown because too many files have changed in this diff Show More