未验证 提交 6f6a3425 编写于 作者: S silverzoey 提交者: GitHub

Merge pull request #2 from CyC2018/master

update
......@@ -12,7 +12,7 @@
由于不同的机器有不同的操作系统,以及不同的库和组件,在将一个应用部署到多台机器上需要进行大量的环境配置操作。
Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程进行隔离,被隔离的进程独立于宿主操作系统和其它隔离的进程。使用 Docker 可以不修改应用程序代码,不需要开发人员学习特定环境下的技术,就能够将现有的应用程序部署在其他机器中
Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程进行隔离,被隔离的进程独立于宿主操作系统和其它隔离的进程。使用 Docker 可以不修改应用程序代码,不需要开发人员学习特定环境下的技术,就能够将现有的应用程序部署在其它机器上
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png" width="400px"/> </div><br>
......@@ -20,19 +20,17 @@ Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程
虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png" width="250px"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7e873b60-44dc-4911-b080-defd5b8f0b49.png" width="250"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/be608a77-7b7f-4f8e-87cc-f2237270bf69.png" width="500"/> </div><br>
## 启动速度
启动虚拟机需要启动虚拟机的操作系统,再启动应用,这个过程非常慢;
启动虚拟机需要启动虚拟机的操作系统,再启动应用,这个过程非常慢;
而启动 Docker 相当于启动宿主操作系统上的一个进程。
## 占用资源
虚拟机是一个完整的操作系统,需要占用大量的磁盘、内存和 CPU,一台机器只能开启几十个的虚拟机。
虚拟机是一个完整的操作系统,需要占用大量的磁盘、内存和 CPU 资源,一台机器只能开启几十个的虚拟机。
而 Docker 只是一个进程,只需要将应用以及相关的组件打包,在运行时占用很少的资源,一台机器可以开启成千上万个 Docker。
......@@ -42,11 +40,11 @@ Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程
## 更容易迁移
提供一致性的运行环境可以在不同的机器上进行迁移,而不用担心环境变化导致无法运行。
提供一致性的运行环境。已经打包好的应用可以在不同的机器上进行迁移,而不用担心环境变化导致无法运行。
## 更容易维护
使用分层技术和镜像,使得应用可以更容易复用重复部分。复用程度越高,维护工作也越容易。
使用分层技术和镜像,使得应用可以更容易复用重复部分。复用程度越高,维护工作也越容易。
## 更容易扩展
......
......@@ -47,14 +47,14 @@ Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本
- git reset -- files 使用当前分支上的修改覆盖暂存区,用来撤销最后一次 git add files
- git checkout -- files 使用暂存区的修改覆盖工作目录,用来撤销本地修改
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/11a786f0-5e02-46a6-92f0-f302c9cf6ca3_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/11a786f0-5e02-46a6-92f0-f302c9cf6ca3_200.png" width="400px"> </div><br>
可以跳过暂存区域直接从分支中取出修改,或者直接提交修改到分支中。
- git commit -a 直接把所有文件的修改添加到暂存区然后执行提交
- git checkout HEAD -- files 取出最后一次修改,可以用来进行回滚操作
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b48b9a7a-f9f8-4cf9-90f1-5cddd685b782_200.png"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b48b9a7a-f9f8-4cf9-90f1-5cddd685b782_200.png" width="600px"> </div><br>
# 分支实现
......
......@@ -776,7 +776,7 @@ GET 用于获取资源,而 POST 用于传输实体主体。
GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高,因为照样可以通过一些抓包工具(Fiddler)查看。
因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如 `中文` 会转换为 `%E4%B8%AD%E6%96%87`,而空格会转换为 `%20`。POST 参支持标准字符集。
因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如 `中文` 会转换为 `%E4%B8%AD%E6%96%87`,而空格会转换为 `%20`。POST 参支持标准字符集。
```
GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1
......
......@@ -53,7 +53,7 @@
- double/64
- boolean/\~
boolean 只有两个值:true、false,可以使用 1 bit 来存储,但是具体大小没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int,使用 1 来表示 true,0 表示 false。JVM 并不直接支持 boolean 数组,而是使用 byte 数组来表示 int 数组来表示
boolean 只有两个值:true、false,可以使用 1 bit 来存储,但是具体大小没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int,使用 1 来表示 true,0 表示 false。JVM 支持 boolean 数组,但是是通过读写 byte 数组来实现的
- [Primitive Data Types](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)
- [The Java® Virtual Machine Specification](https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf)
......@@ -670,10 +670,29 @@ SuperExtendExample.func()
为了满足里式替换原则,重写有有以下两个限制:
- 子类方法的访问权限必须大于等于父类方法;
- 子类方法的返回类型必须是父类方法返回类型或为其子类型。
使用 @Override 注解,可以让编译器帮忙检查是否满足上面的三个限制条件。
使用 @Override 注解,可以让编译器帮忙检查是否满足上面的两个限制条件。
下面的示例中,SubClass 为 SuperClass 的子类,SubClass 重写了 SuperClass 的 func() 方法。其中:
- 子类方法访问权限为 public,大于父类的 protected。
- 子类的返回类型为 ArrayList<Integer>,是父类返回类型 List<Integer> 的子类。
- 子类抛出的异常类型为 Exception,是父类抛出异常 Throwable 的子类。
- 子类重写方法使用 @Override 注解,从而让编译器自动检查是否满足限制条件。
```java
class SuperClass {
protected List<Integer> func() throws Throwable {
return new ArrayList<>();
}
}
class SubClass extends SuperClass {
@Override
public ArrayList<Integer> func() throws Exception {
return new ArrayList<>();
}
}
```
**2. 重载(Overload)**
......
......@@ -20,6 +20,7 @@
# 一、概览
容器主要包括 Collection 和 Map 两种,Collection 存储着对象的集合,而 Map 存储着键值对(两个对象)的映射表。
## Collection
......@@ -114,7 +115,7 @@ List list = Arrays.asList(1, 2, 3);
### 1. 概览
实现了 RandomAccess 接口,因此支持随机访问。这是理所当然的,因为 ArrayList 是基于数组实现的
因为 ArrayList 是基于数组实现的,所以支持快速随机访问。RandomAccess 接口标识着该类支持快速随机访问
```java
public class ArrayList<E> extends AbstractList<E>
......
......@@ -73,7 +73,7 @@
包含了操作系统线程状态中的 Running 和 Ready。
## 阻塞(Blocking
## 阻塞(Blocked
等待获取一个排它锁,如果其线程释放了锁就会结束此状态。
......@@ -1198,7 +1198,7 @@ public static void main(String[] args) throws InterruptedException {
可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。
主要有三种实现可见性的方式:
主要有三种实现可见性的方式:
- volatile
- synchronized,对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。
......
......@@ -129,7 +129,7 @@ public class Test {
}
```
在上述代码中,a与b引用的对象实例互相持有了对象的引用,因此当我们把对a对象与b对象的引用去除之后,由于两个对象还存在互相之间的引用,导致两个Test对象无法被回收。
在上述代码中,a 与 b 引用的对象实例互相持有了对象的引用,因此当我们把对 a 对象与 b 对象的引用去除之后,由于两个对象还存在互相之间的引用,导致两个 Test 对象无法被回收。
### 2. 可达性分析算法
......@@ -214,7 +214,7 @@ obj = null;
```java
Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
PhantomReference<Object> pf = new PhantomReference<Object>(obj, null);
obj = null;
```
......@@ -234,12 +234,18 @@ obj = null;
### 2. 标记 - 整理
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_2001550547456403.png"/> </div><br>
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
优点:
- 不会产生内存碎片
不足:
- 需要移动大量对象,处理效率比较低。
### 3. 复制
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4_2001550547640585.png"/> </div><br>
......@@ -374,7 +380,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
## Minor GC 和 Full GC
- Minor GC:回收新生代,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行,执行的速度一般也会比较快。
- Minor GC:回收新生代,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行,执行的速度一般也会比较快。
- Full GC:回收老年代和新生代,老年代对象其存活时间长,因此 Full GC 很少执行,执行速度会比 Minor GC 慢很多。
......@@ -382,7 +388,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
### 1. 对象优先在 Eden 分配
大多数情况下,对象在新生代 Eden 区分配,当 Eden 区空间不够时,发起 Minor GC。
大多数情况下,对象在新生代 Eden 上分配,当 Eden 空间不够时,发起 Minor GC。
### 2. 大对象直接进入老年代
......@@ -390,7 +396,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
经常出现大对象会提前触发垃圾收集以获取足够的连续空间分配给大对象。
-XX:PretenureSizeThreshold,大于此值的对象直接在老年代分配,避免在 Eden 区和 Survivor 区之间的大量内存复制。
-XX:PretenureSizeThreshold,大于此值的对象直接在老年代分配,避免在 Eden 和 Survivor 之间的大量内存复制。
### 3. 长期存活的对象进入老年代
......@@ -400,13 +406,13 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
### 4. 动态对象年龄判定
虚拟机并不是永远要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升老年代,如果在 Survivor 中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,无需等到 MaxTenuringThreshold 中要求的年龄。
虚拟机并不是永远要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升老年代,如果在 Survivor 中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,无需等到 MaxTenuringThreshold 中要求的年龄。
### 5. 空间分配担保
在发生 Minor GC 之前,虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果条件成立的话,那么 Minor GC 可以确认是安全的。
如果不成立的话虚拟机会查看 HandlePromotionFailure 设置值是否允许担保失败,如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC;如果小于,或者 HandlePromotionFailure 设置不允许冒险,那么就要进行一次 Full GC。
如果不成立的话虚拟机会查看 HandlePromotionFailure 的值是否允许担保失败,如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC;如果小于,或者 HandlePromotionFailure 的值不允许冒险,那么就要进行一次 Full GC。
## Full GC 的触发条件
......@@ -424,7 +430,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
### 3. 空间分配担保失败
使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果担保失败会执行一次 Full GC。具体内容请参考上面的第小节。
使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果担保失败会执行一次 Full GC。具体内容请参考上面的第 5 小节。
### 4. JDK 1.7 及以前的永久代空间不足
......@@ -440,7 +446,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
# 四、类加载机制
类是在运行期间第一次使用时动态加载的,而不是一次性加载。因为如果一次性加载,那么会占用很多的内存。
类是在运行期间第一次使用时动态加载的,而不是一次性加载所有类。因为如果一次性加载,那么会占用很多的内存。
## 类的生命周期
......@@ -514,8 +520,6 @@ public static final int value = 123;
初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段是虚拟机执行类构造器 &lt;clinit>() 方法的过程。在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。
在准备阶段,已经为类变量分配了系统所需的初始值,并且在初始化阶段,根据程序员通过程序进行的主观计划来初始化类变量和其他资源。
&lt;clinit>() 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码:
```java
......@@ -617,7 +621,7 @@ System.out.println(ConstClass.HELLOWORLD);
应用程序是由三种类加载器互相配合从而实现类加载,除此之外还可以加入自己定义的类加载器。
下图展示了类加载器之间的层次关系,称为双亲委派模型(Parents Delegation Model)。该模型要求除了顶层的启动类加载器外,其它的类加载器都要有自己的父类加载器。类加载器之间的父子关系一般通过组合关系(Composition)来实现,而不是继承关系(Inheritance)。
下图展示了类加载器之间的层次关系,称为双亲委派模型(Parents Delegation Model)。该模型要求除了顶层的启动类加载器外,其它的类加载器都要有自己的父类加载器。这里的父子关系一般通过组合关系(Composition)来实现,而不是继承关系(Inheritance)。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/805812fa-6ab5-4b8f-a0aa-3bdcadaa829d.png"/> </div><br>
......@@ -681,7 +685,7 @@ public abstract class ClassLoader {
## 自定义类加载器实现
FileSystemClassLoader 是自定义类加载器,继承自 java.lang.ClassLoader,用于加载文件系统上的类。它首先根据类的全名在文件系统上查找类的字节代码文件(.class 文件),然后读取该文件内容,最后通过 defineClass() 方法来把这些字节代码转换成 java.lang.Class 类的实例。
以下代码中的 FileSystemClassLoader 是自定义类加载器,继承自 java.lang.ClassLoader,用于加载文件系统上的类。它首先根据类的全名在文件系统上查找类的字节代码文件(.class 文件),然后读取该文件内容,最后通过 defineClass() 方法来把这些字节代码转换成 java.lang.Class 类的实例。
java.lang.ClassLoader 的 loadClass() 实现了双亲委派模型的逻辑,自定义类加载器一般不去重写它,但是需要重写 findClass() 方法。
......
......@@ -349,7 +349,7 @@ Redis 这种内存型数据库的读写性能非常高,很适合存储频繁
## 消息队列
List 是一个双向链表,可以通过 lpop 和 lpush 写入和读取消息。
List 是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息。
不过最好使用 Kafka、RabbitMQ 等消息中间件。
......@@ -363,7 +363,7 @@ List 是一个双向链表,可以通过 lpop 和 lpush 写入和读取消息
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。
可以使用 Reids 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
## 其它
......@@ -405,7 +405,7 @@ Redis 可以为每个键设置过期时间,当键过期时,会自动删除
可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。
Reids 具体有 6 种淘汰策略:
Redis 具体有 6 种淘汰策略:
| 策略 | 描述 |
| :--: | :--: |
......@@ -555,7 +555,7 @@ Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入
分片是将数据划分为多个部分的方法,可以将数据存储到多台机器里面,这种方法在解决某些问题时可以获得线性级别的性能提升。
假设有 4 个 Reids 实例 R0,R1,R2,R3,还有很多表示用户的键 user:1,user:2,... ,有不同的方式来选择一个指定的键存储在哪个实例中。
假设有 4 个 Redis 实例 R0,R1,R2,R3,还有很多表示用户的键 user:1,user:2,... ,有不同的方式来选择一个指定的键存储在哪个实例中。
- 最简单的方式是范围分片,例如用户 id 从 0\~1000 的存储到实例 R0 中,用户 id 从 1001\~2000 的存储到实例 R1 中,等等。但是这样需要维护一张映射范围表,维护操作代价很高。
- 还有一种方式是哈希分片,使用 CRC32 哈希函数将键转换为一个数字,再对实例数量求模就能知道应该存储的实例。
......
......@@ -318,7 +318,7 @@ private void swap(TreeNode root) {
# 28 对称的二叉树
[NowCder](https://www.nowcoder.com/practice/ff05d44dfdb04e1d83bdbdab320efbcb?tpId=13&tqId=11211&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
[NowCoder](https://www.nowcoder.com/practice/ff05d44dfdb04e1d83bdbdab320efbcb?tpId=13&tqId=11211&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
## 题目描述
......
......@@ -12,7 +12,7 @@
## 依赖管理
不再需要手动导入 Jar 依赖包,并且可以自动处理依赖关系,也就是说某个依赖如果依赖于其它依赖,构建工具可以帮助我们自动处理这种依赖管理
不再需要手动导入 Jar 依赖包,并且可以自动处理依赖关系,也就是说某个依赖如果依赖于其它依赖,构建工具可以帮助我们自动处理这种依赖关系
## 运行单元测试
......
......@@ -602,6 +602,7 @@ public Node rotateLeft(Node h) {
public Node rotateRight(Node h) {
Node x = h.left;
h.left = x.right;
x.right = h;
x.color = h.color;
h.color = RED;
x.N = h.N;
......
......@@ -8,6 +8,7 @@
# 编译系统
以下是一个 hello.c 程序:
```c
......
......@@ -85,11 +85,13 @@ SMTP 只能发送 ASCII 码,而互联网邮件扩充 MIME 可以发送二进
## 2. POP3
POP3 的特点是只要用户从服务器上读取了邮件,就把该邮件删除。
POP3 的特点是只要用户从服务器上读取了邮件,就把该邮件删除,但是目前改进的 POP3 已经全面支持下载而不删除原邮件。
它的另一个主要特点是:无论你在客户端做了任何操作(如移动、标记),都不会反映到服务器上,也就是只能单方面地从服务器“读取”。
## 3. IMAP
IMAP 协议中客户端和服务器上的邮件保持同步,如果不手动删除邮件,那么服务器上的邮件也不会被删除。IMAP 这种做法可以让用户随时随地去访问服务器上的邮件。
IMAP 协议中客户端和服务器上的邮件保持同步,如果不手动删除邮件,那么服务器上的邮件也不会被自动删除。IMAP 这种做法可以让用户随时随地去访问服务器上的邮件。
同时它与 POP3 的本质区别在于,在客户端的操作(包括删除)都会反映到服务器上,是一个双向的通信。
# 常用端口
......
......@@ -107,9 +107,9 @@
其中表示层和会话层用途如下:
- **表示层** :数据压缩和解压缩、加密和解密以及数据格式变化等,这使得应用程序不必关心在各台主机中数据内部格式不同的问题。
- **表示层** :数据压缩、加密以及数据描述,这使得应用程序不必关心在各台主机中数据内部格式不同的问题。
- **会话层** :建立及管理和终止会话。
- **会话层** :建立及管理会话。
五层协议没有表示层和会话层,而是将这些功能留给应用程序开发者处理。
......
......@@ -65,7 +65,7 @@
互联网服务提供商 ISP 可以从互联网管理机构获得许多 IP 地址,同时拥有通信线路以及路由器等联网设备,个人或机构向 ISP 缴纳一定的费用就可以接入互联网。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7_2001550811502556.png" width="500"/> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/68d76d01-f11f-4f6e-85ae-b9db4368d544_200.png" width="500"/> </div><br>
目前的互联网是一种多层次 ISP 结构,ISP 根据覆盖面积的大小分为第一层 ISP、区域 ISP 和接入 ISP。互联网交换点 IXP 允许两个 ISP 直接相连而不用经过第三个 ISP。
......@@ -144,9 +144,9 @@
其中表示层和会话层用途如下:
- **表示层** :数据压缩、加密以及数据描述,这使得应用程序不必关心在各台主机中数据内部格式不同的问题。
- **表示层** :数据压缩和解压缩、加密和解密以及数据格式变化等,这使得应用程序不必关心在各台主机中数据内部格式不同的问题。
- **会话层** :建立及管理会话。
- **会话层** :建立及管理和终止会话。
五层协议没有表示层和会话层,而是将这些功能留给应用程序开发者处理。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册