学习笔记2

1. 分享:Java垃圾回收机制

1、经常使用垃圾回收机制

1. 标记-清除算法(mark-sweep)

顾名思义,标记-清除算法分为两个阶段,标记(mark)和清除(sweep).html

在标记阶段,collector从mutator根对象开始进行遍历,对从mutator根对象能够访问到的对象都打上一个标识,通常是在对象的header中,将其记录为可达对象。java

而在清除阶段,collector对堆内存(heap memory)从头至尾进行线性的遍历,若是发现某个对象没有标记为可达对象-经过读取对象的header信息,则就将其回收。node

img

从上图咱们能够看到,在Mark阶段,从根对象1能够访问到B对象,从B对象又能够访问到E对象,因此B,E对象都是可达的。同理,F,G,J,K也都是可达对象。到了Sweep阶段,全部非可达对象都会被collector回收。同时,Collector在进行标记和清除阶段时会将整个应用程序暂停(mutator),等待标记清除结束后才会恢复应用程序的运行。linux

缺点web

​ 标记-清除算法的比较大的缺点就是垃圾收集后有可能会形成大量的内存碎片,像上面的图片所示,垃圾收集后内存中存在三个内存碎片,假设一个方格表明1个单位的内存,若是有一个对象须要占用3个内存单位的话,那么就会致使Mutator一直处于暂停状态,而Collector一直在尝试进行垃圾收集,直到Out of Memory。算法

2. 标记-压缩算法(mark-compact)

​ 顾名思义,标记-压缩算法分为两个阶段,标记(mark)和压缩(compact).sql

​ 其中标记阶段跟标记-清除算法中的标记阶段是同样的,而对于压缩阶段,它的工做就是移动全部的可达对象到堆内存的同一个区域中,使他们紧凑的排列在一块儿,从而将全部非可达对象释放出来的空闲内存都集中在一块儿,经过这样的方式来达到减小内存碎片的目的。数据库

img

3. 复制算法(copying)

堆内存对半分为两个半区,只用其中一个半区来进行对象内存的分配,若是在这个半区内存不够给新的对象分配了,那么就开始进行垃圾收集,将这个半区中的全部可达对象都拷贝到另一个半区中去,而后继续在另外那个半区进行新对象的内存分配。express

img

mg

**缺点: **编程

​ 内存压缩为原来的一半,利用率比较低,典型的空间换时间

4. 引用计数算法(reference counting)

​ 经过在对象头中分配一个空间来保存该对象被引用的次数。若是该对象被其它对象引用,则它的引用计数加一,若是删除对该对象的引用,那么它的引用计数就减一,当该对象的引用计数为0时,那么该对象就会被回收。

​ 采用引用计数的垃圾收集机制跟前面三种垃圾收集机制最大的不一样在于,垃圾收集的开销被分摊到整个应用程序的运行当中了,而不是在进行垃圾收集时,要挂起整个应用的运行,直到对堆中全部对象的处理都结束。所以,采用引用计数的垃圾收集不属于严格意义上的"Stop-The-World"的垃圾收集机制。

注意:

  • 当某个对象的引用计数减为0时,collector须要递归遍历它所指向的全部域,将它全部域所指向的对象的引用计数都减一,而后才能回收当前对象。

  • 可是这种引用计数算法有一个比较大的问题,那就是它不能处理环形数据 - 即若是有两个对象相互引用,那么这两个对象就不能被回收,由于它们的引用计数始终为1。这也就是咱们常说的“内存泄漏”问题。以下图:

    img

5. 分代收集算法

​ 当前的商业虚拟机都采用的是”分代收集“算法,通常是把java堆分红新生代和老生代,这样就能够根据各个年代的特色采用最适当的垃圾收集算法,新生代中,对象大可能是”朝生夕死“能够采用复制算法,而老年代的对象存活率比较高,并且没有担保空间进行内存分配,就要采用”标记-清除算法“或者”标记-整理“算法。

## 2、Java垃圾回收

1. Java的内存分布

img

其中,堆内存分为年轻代和年老代,非堆内存主要是Permanent区域,主要用于存储一些类的元数据,常量池等信息。而年轻代又分为两种,一种是Eden区域,另一种是两个大小对等的Survivor区域。

2. Java年轻代垃圾回收机制

img

​ 部分的新建立对象分配在新生代。由于大部分对象很快就会变得不可达,因此它们被分配在新生代,而后消失再也不。当对象重新生代移除时,咱们称之为"Minor GC"。新生代使用的是复制收集算法

​ 新生代划分为三个部分:分别为Eden、Survivor from、Survivor to,大小比例为8:1:1(为了防止复制收集算法的浪费内存过大)。每次只使用Eden和其中的一块Survivor,回收时将存活的对象复制到另外一块Survivor中,这样就只有10%的内存被浪费,可是若是存活的对象总大小超过了Survivor的大小,那么就把多出的对象放入老年代中。

在三个区域中有两个是Survivor区。对象在三个区域中的存活过程以下:

  1. 大多数新生对象都被分配在Eden区。
  2. 第一次GC事后Eden中还存活的对象被移到其中一个Survivor区。
  3. 再次GC过程当中,Eden中还存活的对象会被移到以前已移入对象的Survivor区。
  4. 一旦该Survivor区域无空间可用时,还存活的对象会从当前Survivor区移到另外一个空的Survivor区。而当前Survivor区就会再次置为空状态。
  5. 通过数次(默认是15次)在两个Survivor区域移动后还存活的对象最后会被移动到老年代。

如上所述,两个Survivor区域在任什么时候候一定有一个保持空白。若是同时有数据存在于两个Survivor区或者两个区域的的使用量都是0,则意味着你的系统可能出现了运行错误。

3. Java老年代垃圾回收机制

​ 存活在新生代中但未变为不可达的对象会被复制到老年代。通常来讲老年代的内存空间比新生代大,因此在老年代GC发生的频率较新生代低一些。当对象从老年代被移除时,咱们称之为 "Major GC"(或者Full GC)。 老年代使用标记-清理或标记-整理算法

空间分配担保

在发生Minor GC前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代全部对象总空间。

  1. 若是大于,那么Minor GC能够确保是安全的。

  2. 若是小于,虚拟机会查看HandlePromotionFailure设置值是否容许担任失败。

    • 若是容许,那么会继续检查老年代最大可用连续空间是否大于历次晋升老年代对象的平均大小
      • 若是大于,将尝试着进行一次Minor GC,尽管此次Minor GC是有风险的
      • 若是小于,进行一次Full GC
    • 若是不容许,也要改成进行一次Full GC

    ​ 前面提到过,新生代使用复制收集算法,但为了内存利用率,只使用其中一个Survivor空间来做为轮换备份,所以当出现大量对象在Minor GC后仍然存活的状况时(最极端就是内存回收后新生代中全部对象都存活),就须要老年代进行分配担保,让Survivor没法容纳的对象直接进入老年代。与生活中的贷款担保相似,老年代要进行这样的担保,前提是老年代自己还有容纳这些对象的剩余空间,一共有多少对象会活下来,在实际完成内存回收以前是没法明确知道的,因此只好取以前每一次回收晋升到老年代对象容量的平均大小值做为经验值,与老年代的剩余空间进行比较,决定是否进行Full GC来让老年代腾出更多空间。

    ​ 取平均值进行比较其实仍然是一种动态几率的手段,也就是说若是某次Minor GC存活后的对象突增,远远高于平均值的话,依然会致使担保失败(Handle Promotion Failure)。若是出现了HandlePromotionFailure失败,那就只好在失败后从新发起一次Full GC。虽然担保失败时绕的圈子是最大的,但大部分状况下都仍是会将HandlePromotionFailure开关打开,避免Full GC过于频繁。

2.Java垃圾收集器

img

  • Serial收集器(Serial/Serial Old)

    Serial是一个单线程的收集器,但它的“单线程”意义并不只仅说明它只会使用一个CPU或一条手机此案成去完成垃圾和收集工做,更重要的是它进行垃圾收集时,必须暂停其余全部的工做线程,直到它收集结束。

    img

  • ParNew收集器

    ParNew收集器其实就是Serial收集器的多线程版本。

    它是运行在Server模式下的虚拟机中首选的新生代收集器,其中有一个与性能无关但很重要的缘由是:除了Serial收集器外,目前只有它能与CMS收集器配合工做。

    img

  • Parallel Scavenge收集器

    ​ 该收集器也是一个新生代的垃圾收集器,他也是使用复制算法的收集器,又是一个并行的垃圾收集器。该收集器的特色是他的关注点与其余的收集器不一样,CMS等收集器的关注点是尽量缩短垃圾回收时用户线程的停顿时间,而parallel Scavenge收集器的目标是达到一个可控制的吞吐量。所谓吞吐量就是CPU用于运行代码的时间与CPU总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾回收时间),好比虚拟机总共运行100分钟,垃圾回收占用了1分钟,那么吞吐量就是99%。

  • Parallel Old收集器

    Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。

    img

  • CMS收集器

    CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。CMS是基于“标记-清除”算法实现的,它的运做过程相对于前面几种收集器来讲更复杂一些,整个过程分为4个步骤,包括:

    • 初始标记(CMS initial mark)
    • 并发标记(CMS concurrent mark)
    • 从新标记(CMS remark)
    • 并发清除(CMS concurrent sweep)

    其中,初始标记、从新标记这两个步骤仍然须要”Stop The world”。初始标记仅仅只是标记一下GC Roots Tracing的过程,而从新标记阶段则是为了修正并发标记期间因用户程序继续运做而致使标记产生变更的那一部分对象的标记记录,这个阶段的停顿时间通常会比初始标记阶段稍长一些,但远比并发标记的时间短。

    因为整个过程当中耗时最长的并发标记和并发清除过程收集器线程均可以与用户线程一块儿工做,因此,从整体上来讲,CMS收集器的内存回收过程是与用户线程一块儿并发执行的。

    img

    **CMS的优点:**并发收集、低停顿。

    CMS的缺点:

    • 对CPU资源很是敏感。CMS默认启动的回收线程数是(CPU数量 + 3)/4,并发回收时垃圾收集线程所占CPU资源随着CPU数量的增长而降低,并且在CPU不足4个时,CMS对用户程序的影响就可能变得很大,致使执行速度下降。
    • CMS收集器没法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而致使另外一次Full GC的产生。
    • CMS是一款基于“标记-清除”算法实现的收集器,这意味着收集结束时会有大量空间碎片产生。空间碎片太多的时候,将会给大对象分配带来很大麻烦。
  • G1收集器

    G1是一款面向服务端应用的垃圾收集器。HOtSpot开发团队赋予它的使命是将来能够替换掉CMS收集器。

    G1具有以下特色:

    • **并行与并发:**G1能充分利用多CPU、多核环境下的硬件优点,使用多个CPU来缩短Stop-The-World停顿的时间,部分其余收集器本来须要停顿Java线程执行的GC动做,G1收集器仍然能够经过并发的方式让Java程序继续执行。
    • **分代收集:**虽然G1能够不须要其余收集器配合就能独立管理整个GC堆,但它可以采用不一样的方式去处理新建立的对象和已经存活了一段时间、熬过屡次GC的就对象以获取更好的收集效果。
    • 空间整合:G1从总体上来看是基于“标记-整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的,这意味着G1运做期间不会产生内存空间碎片,收集后能提供规整的可用内存。
    • 可预测的停顿:这是G1相对于CMS的另外一大优点。

    G1垃圾收集器和CMS垃圾收集器有几点不一样。首先,最大的不一样是内存的组织方式变了。Eden,Survivor和Tenured等内存区域再也不是连续的了,而是变成了一个个大小同样的region - 每一个region从1M到32M不等。

    img

    一个region有可能属于Eden,Survivor或者Tenured内存区域。图中的E表示该region属于Eden内存区域,S表示属于Survivor内存区域,T表示属于Tenured内存区域。图中空白的表示未使用的内存空间。G1垃圾收集器还增长了一种新的内存区域,叫作Humongous内存区域,如图中的H块。这种内存区域主要用于存储大对象-即大小超过一个region大小的50%的对象。

    在G1垃圾收集器中,年轻代的垃圾回收过程跟PS垃圾收集器和CMS垃圾收集器差很少。

    img

    对于年老代上的垃圾收集,G1垃圾收集器也分为4个阶段,基本跟CMS垃圾收集器同样,但略有不一样:

    1. Initial Mark阶段 - 同CMS垃圾收集器的Initial Mark阶段同样,G1也须要暂停应用程序的执行,它会标记从根对象出发,在根对象的第一层孩子节点中标记全部可达的对象。可是G1的垃圾收集器的Initial Mark阶段是跟minor gc一同发生的。也就是说,在G1中,你不用像在CMS那样,单独暂停应用程序的执行来运行Initial Mark阶段,而是在G1触发minor gc的时候一并将年老代上的Initial Mark给作了。

    2. Concurrent Mark阶段 - 在这个阶段G1作的事情跟CMS同样。但G1同时还多作了一件事情,那就是,若是在Concurrent Mark阶段中,发现哪些Tenured region中对象的存活率很小或者基本没有对象存活,那么G1就会在这个阶段将其回收掉,而不用等到后面的clean up阶段。这也是Garbage First名字的由来。同时,在该阶段,G1会计算每一个 region的对象存活率,方便后面的clean up阶段使用 。

    3. Remark阶段 - 在这个阶段G1作的事情跟CMS同样, 可是采用的算法不一样,可以在Remark阶段更快的标记可达对象。

    4. Clean up/Copy阶段 - 在G1中,没有CMS中对应的Sweep阶段。相反 它有一个Clean up/Copy阶段,在这个阶段中,G1会挑选出那些对象存活率低的region进行回收,这个阶段也是和minor gc一同发生的,以下图所示:

      img

    从上能够看到,因为Initial Mark阶段和Clean up/Copy阶段都是跟minor gc同时发生的,相比于CMS,G1暂停应用程序的时间更少,从而提升了垃圾回收的效率。

2. Octave学习

  1. 内建基本数学函数

    cos   余弦函数 (弧度制) sin    正弦函数 (弧度制) tan    正切函数 (弧度制) exp    指数函数 (e x ) log    以 e 为底的指数函数 log10   以 10 为底的指数函数  sinh    双曲正弦函数 tanh    双曲正切函数 cosh    双曲余弦函数 acos    反余弦函数 acosh   反双曲余弦函数 asin    反正弦函数 asinh   反双曲正弦函数 atan    反正切函数 atanh    反双曲正切函数 abs     绝对值函数 (复数取模) round     四舍五入 floor     近似为比它小的最大整数 ceil      近似为比它大的最小整数 fix       向 0 方向近似 rem      求余数

  2. 变量

    Octave 中变量的类型是不用声明的。Octave 全部的变量都是浮点型或者字符串。

    如:deg=pi/180

    注:ans 变量存储你每次最近运算的结果。

  3. 数组和向量

    1. 构造向量

    示例:a = [1 4 5] b = [1, 4, 5] c = [1; 4; 5] 在方括号中由空格或者逗号隔开的一组数据被定义为行向量; 而由分号或者回车隔开的一组数据被定义为列向量

    1. 冒号表达式

      示例:a = 2: 6 即 a = [2 3 4 5 6]

      ​ a = 2: 0.5: 4 即 a = [2.0000 2.5000 3.0000 3.5000 4.0000]

    2. 向量中的元素操做

      a=[1:2:6 -1 0] 则 a(3) 为 5

      注:向量中的元素经过括号 (),而第一个元素的编号为 1

    3. 向量计算

      使用 +− 算符,你一样能够对该向量中的每一个元素都加上或者减去一个数值。

      两个向量的相乘遵循矩阵的乘法法则,向量乘法并非对应元素的相乘。若是要进行对应元素的乘除法,你能够使用

      .* 和 ./ (注意前面有个点)

  4. 基本画图命令: plot(x, y) x为横轴,y为纵轴

  5. 控制语句

    判断语句:if expression ​ statements ​ elseif ​ expression ​ statements

    ​ else ​ statements ​ end

    switch语句 :switch x

    ​ case x1 ​ statements ​ case x2 ​ statements ​ otherwise ​ statements ​ end

    for 循环:for variable=vector ​ statements ​ end

    while循环:while expression ​ statements ​ end

  6. 函数

    示例:function s=sind(x) ​ % SIND(x) Calculates sine(x) in degrees ​ s=sin(x*pi/180); ​ endfunction

  7. 矩阵和向量

    • 矩阵构建

    ​ 在 Octave 中输入矩阵与输入向量类似,逐行输入: ​ octave:##> A= [ 5 7 9 ​ -1 3 -2 ]

    ​ 或者使用分号来标定一行的结束,例如: ​ octave:##> B=[2 0; 0 -1; 1 0] ​ octave:##> B= ​ 2 0 ​ 0 -1 ​ 1 0

    ​ 其余: 单位矩阵建立: I = eye(4)

    ​ 对角矩阵建立: M = diag([-1 7 4]) -1 7 4 为对角的值

    • 矩阵转置符 如:A'

    • 提取矩阵元

      如: J(1, 3) 1, 3 分别为行号和列号

      ​ J(1:3, 5) 1到3行,第五列

    • 赋值

      如:J(1, 3) = 4

    • 基本矩阵函数

      eye 建立单位矩阵 zeros 建立全零矩阵 ones 建立全一矩阵 rand 建立随机数矩阵 diag 建立一个对角矩阵,或者提取一个矩阵的对角元 inv 求矩阵逆矩阵 trace 求矩阵的迹 rank 求矩阵的秩

3. 吴恩达课程学习

  • 机器学习的两种方式:

    • 有监督学习:相似与我知道一个问题的答案,因此我能够从这个答案问题出发设计出一个推理逻辑。

      受监督的学习问题分为“回归”和“分类”问题。在回归问题中,咱们试图在连续输出中预测结果,这意味着咱们正在尝试将输入变量映射到一些连续函数。在分类问题中,咱们试图用离散输出来预测结果。换句话说,咱们正在尝试将输入变量映射到离散类别。

      示例: 回归 - 鉴于一我的的照片,咱们必须根据给定的图片来预测他们的年龄

          分类 - 鉴于肿瘤患者,咱们必须预测肿瘤是恶性仍是良性

    • 无监督学习:相似于我给你一堆数据,你也不知道它是干什么用的,可是你或许能够找出这些数据中蕴含的某种规律。无监督学习问题可分为聚类和非聚类两种。

      聚类:收集100万个不一样的基因,并找到一种自动将这些基因组合成不一样变量(如寿命,位置,做用等)类似或相关的组。

      非聚类:“鸡尾酒会算法”,让您在混乱的环境中找到结构。(即从鸡尾酒会的声音网格中识别我的的声音和音乐)。

  • 模型表示

    为了更准确地描述监督学习问题,咱们的目标是给出一个训练集,以学习一个函数h:X→Y,使得h(x)是相应的y值的“好”预测因子。因为历史缘由,这个函数h被称为假设。从形象上看,这个过程是这样的:

    img

  • 成本函数

    咱们能够经过使用成本函数来衡量假设函数的准确性。这取决于x的输入和实际输出y的假设的全部结果的平均差别(其实是平均值的平均值)。

    img

  • 梯度降低

    img

    上图中的每一个“星”之间的距离表示由咱们的参数α肯定的步长。较小的α将致使较小的步长,较大的α致使较大的步长。采起步骤的方向由偏导数决定Ĵ(i0,θ1)。根据图上的哪个开始,人们可能会在不一样的地方结束。上图显示了两个不一样的起点,最终出如今两个不一样的地方。

    下图展现了梯度向下的算式,当左式恒等于右式之时,找到局部最优解。

    img

    • 线性回归的梯度降低

      ![2017-10-24 21-50-27屏幕截图](/home/tofar/图片/2017-10-24 21-50-27屏幕截图.png)

      img

      img

      上面所示的椭圆是二次函数的轮廓。还显示了由(48,30)初始化的梯度降低所采起的轨迹。图中的x(由直线链接)标记梯度降低通过的θ的连续值,由于它收敛到最小值。

  • 特征缩放

    们能够经过使咱们的每一个输入值在大体相同的范围内来加快梯度降低。这是由于在较小的范围内,θ会快速降低,而在较大的范围内会慢慢降低,所以当变量很是不均匀时,它会低效地摆动到最佳状态。

    防止这种状况的方法是修改输入变量的范围,使其大体相同。理想的状况是:

    -1 <= X <= 1 或者 -0.5 <= X <= 0.5

    计算公式:

    ![2017-10-26 14-26-15屏幕截图](/home/tofar/图片/2017-10-26 14-26-15屏幕截图.png)

​ 分母为范围。。。。

  • 学习比率

    **调试梯度降低。**在x轴上绘制一个迭代次数的图。如今绘制成本函数J(θ)超过梯度降低次数。若是J(θ)增长,那么您可能须要减小α。

    若是 一 过小:收敛缓慢

    若是 一 太大:每次迭代都不能减小,从而可能不会收敛。

  • 特征和多项式回归

    咱们能够经过几种不一样的方式改进咱们的特征和咱们的假设函数的形式。

    咱们能够多个功能组合成一个。例如,咱们能够结合X1 和 X2 成为新功能 X3 经过服用 X1⋅X2.

    多项式回归

    若是不符合数据,咱们的假设函数不须要是线性的(直线)。

    咱们能够经过使其成为二次,立方或平方根函数(或任何其余形式)来改变假设函数的行为或曲线

    例如,若是咱们的假设函数是 H我(x)= θ0+ θ1X1 那么咱们能够建立基于的附加功能 X1,获得二次函数 H我(x)= θ0+ θ1X1+ θ2X21 或立方函数 H我(x)= θ0+ θ1X1+ θ2X21+ θ3X31

    在立方体版本中,咱们建立了新功能 X2 和 X3 哪里 X2= x21 和 X3= x31.

    为了使其成为平方根函数,咱们能够作: H我(x)= θ0+ θ1X1+ θ2√X1

  • 正规方程法

    计算公式:θ=(XTX)−1XTy

    如下是梯度降低与正态方程的比较:

    梯度降低 正常方程式
    须要选择alpha 不须要选择alpha
    须要不少次迭代 不须要迭代
    T至ñ2) Tñ3),须要计算倒数 XŤX
    当n大时,效果很好 若是n很是大,则慢
  • 正态方程不可逆

​ 当在八度中实现正态方程时,咱们要使用'pinv'函数而不是'inv'。'pinv'功能会给你一个值我 即便 XŤX 是不可逆的

​ 若是 XŤX是**不可逆的,**常见的缘由多是:

  • ​冗余特征,其中两个特征很是密切相关(即它们是线性相关的)
  • ​ 功能太多(例如m≤n)。在这种状况下,删除某些功能或使用“正则化”(稍后将讲解)。

解决上述问题的方法包括删除与另外一个线性相关的特征或者当具备太多特征时删除一个或多个特征。

  • 逻辑回归

    • 成本函数

    咱们不能使用与线性回归相同的成本函数,由于逻辑函数会致使输出波浪形,致使许多局部最优。换句话说,它不会是一个凸函数。

    相反,咱们用于逻辑回归的成本函数以下所示:

    选区_001

    • 优化

      **"Conjugate gradient", "BFGS", and "L-BFGS" **are more sophisticated, faster ways to optimize θ that can be used instead of gradient descent. We suggest that you should not write these more sophisticated algorithms yourself (unless you are an expert in numerical computing) but use the libraries instead, as they're already tested and highly optimized. Octave provides them.

    • 一对多

      因为y = {0,1 ... n},咱们将问题划分为n + 1(+1,由于索引从0开始)二进制分类问题; 在每一个类中,咱们预测'y'是咱们其中一个类的成员的几率。

      y∈{0,1...n}
      h(0)θ(x)=P(y=0|x;θ)
      h(1)θ(x)=P(y=1|x;θ)
      ⋯
      h(n)θ(x)=P(y=n|x;θ)
      prediction=maxi(h(i)θ(x))
      复制代码

      img

    • 过分拟合

      img

      图中左图为欠拟合,中间的图片差很少正好,右图为过拟合

      低估或高误差是当咱们的假设函数的形式h映射到数据的趋势。它一般是由一个功能太简单或功能太少形成的。在另外一个极端,过分拟合或高度变异是由适合可用数据的假设函数引发的,但不能很好地推广以预测新的数据。这一般是由一个复杂的函数形成的,这个函数会产生大量与数据无关的没必要要的曲线和角度。

      有两个主要的选择来解决过分拟合的问题:

      1)减小功能的数量:

      • 手动选择要保留的功能。
      • 使用模型选择算法(在课程后面研究)。

      2)正规化

      • 保留全部功能,但减小参数的大小 θj.
      • 当咱们有不少有用的功能时,正则化运做良好。
    • 正则化和处罚机制

      img

      minθ 12m ∑mi=1(hθ(x(i))−y(i))2+λ ∑nj=1θ2j

      使用上述成本函数与额外的总和,咱们能够平滑咱们的假设函数的输出,以减小过分拟合。若是选择的lambda太大,可能会使功能过于平滑,致使不足。

    • 正规化线性回归

      • 梯度向下

        ...

      • 正规方程

θ=(XTX+λ⋅L)−1XTy

是一个矩阵,左上角为0,下角为1,其余地方为0。它应该有尺寸(n + 1)×(n + 1)。直觉上,这是身份矩阵(虽然咱们不包括在内)X0)乘以单个实数λ。

回想一下,若是m <n,那么 XŤX是不可逆的。可是,当咱们添加术语λ⋅L时,XŤX +λ⋅L变成可逆的。

  • 正则化逻辑回归

    逻辑回归的成本函数:

    ...

    正则化逻辑回归的成本函数:

    ...

    img

  • 神经网络

      1. 模型表示

        让咱们来看看如何使用神经网络来表示一个假设函数。在一个很是简单的层面上,神经元基本上是计算单位,它们将输入(树突)做为输入(轴突)的电输入(称为“尖峰” )。在咱们的模型中,咱们的树突就像输入的特征X1⋯xñ,输出是咱们假设函数的结果。在这个模型中咱们X0输入节点有时被称为“偏置单元”。它老是等于1.在神经网络中,咱们使用与分类中相同的逻辑函数,1/(1 + e- θŤX),但咱们有时将其称为sigmoid(逻辑)激活功能。在这种状况下,咱们的“theta”参数有时被称为“权重”。

        例如:

        img

    ​ Example: If layer 1 has 2 input nodes and layer 2 has 4 activation nodes. Dimension of Θ(1) is going to be 4×3 where sj=2 and sj+1=4, so sj+1×(sj+1)=4×3.

    选区_003

    选区_003

    选区_005

    • 应用

      • Examples and Intuitions I

      an example of the logical operator 'OR', meaning either x1 is true or x~2~ is true, or both:

      img

      Where g(z) is the following:

      img

      • Examples and Intuitions II

        here we have the XNOR operator using a hidden layer with two nodes! The following summarizes the above algorithm:

        img

        • 多类分类

          为了将数据分类到多个类中,咱们假设函数返回值的向量。说咱们想将咱们的数据分为四类。咱们将使用下面的例子来看看这个分类是如何完成的。该算法将图像做为输入并进行相应的分类:

          img

          咱们能够将咱们的结果类定义为y:

          img

          img

        • 代价函数

          选区_006

          注意:

          • 双重数额简单地将输出层中每一个单元格的逻辑回归成本加起来
          • 三元组简单地将整个网络中全部单个Θ的平方相加。
          • 我在三合一中并非指训练示例i
        • 反向传播算法

          https://www.coursera.org/learn/machine-learning/supplement/pjdBA/backpropagation-algorithm

          https://www.coursera.org/learn/machine-learning/supplement/v5Bu8/backpropagation-intuition

          img

          img

        • 梯度检验

          gradApprox矢量计算方法:

          A small value for ϵ (epsilon) such as ϵ=10^−4^, guarantees that the math works out properly.

          epsilon = 1e-4;
          for i = 1:n,
            thetaPlus = theta;
            thetaPlus(i) += epsilon;
            thetaMinus = theta;
            thetaMinus(i) -= epsilon;
            gradApprox(i) = (J(thetaPlus) - J(thetaMinus))/(2*epsilon)
          end;
          复制代码

          一旦咱们计算咱们的gradApprox矢量,咱们能够检查gradApprox≈deltaVector。

          一旦你已经验证**,一旦**你的BP算法是正确的,则不须要再次计算gradApprox。计算gradApprox的代码可能很是慢。

        • 随机初始化

          将全部的权重初始化为零不适用于神经网络。反向传播时,全部节点将重复更新为相同的值。相反,咱们能够随机初始化咱们的权重钍 矩阵使用如下方法:

          img

        • 培训一个神经网络

          1. 随机初始化权重
          2. 实现向前传播获得hΘ(x(i)) 对于任何y x(i)
          3. 实施成本函数
          4. 实施反向传播以计算偏导数
          5. 使用梯度检查来确认您的反向传播的做品。而后禁用梯度检查。
          6. 使用梯度降低或内置的优化功能,以theta中的权重最小化成本函数。

4. linux 命令学习

  • cat

    1. 一次显示整个文件。$ cat filename
    2. 从键盘建立一个文件。$ cat > filename

    ​ 注:只能建立新文件,不能编辑已有文件.

    1. 将几个文件合并为一个文件: $cat file1 file2 > file

      参数:

      -n 或 --number 由 1 开始对全部输出的行数编号 -b 或 --number-nonblank 和 -n 类似,只不过对于空白行不编号 -s 或 --squeeze-blank 当遇到有连续两行以上的空白行,就代换为一行的空白行

    2. 建立文件,建立文件后,要以EOF或STOP结束;如:$ cat > linuxsir.org.txt << EOF

    3. 追加内容 如:$ cat >> linuxsir.txt << EOF

    4. 一个或多个已存在的文件内容,追加到一个已存在的文件中

      如:$ cat sir01.txt sir02.txt sir03.txt >> sir00.txt (与 cat sir01.txt sir02.txt sir03.txt > sir04.txt 区分,此为合并)

5. 用户组和权限

  • 文件属性

    - rwx r-x r--

    1 234 567 890

    1表明问文件名或者目录, 234表明拥有者的权限,可读、可写、可执行(rwx),567表明同用户组权限,890表明其余用户权限

    改变文件属性和权限

    chgrp: 改变文件所属用户组

    chown:改变文件全部者 例如: chown [-R] 帐号名称 文件或者目录 (-R 递归)

    chmod:改变文件权限

    ​ 权限分数: r : 4 w: 2 x:1

    ​ 例如: chmod 777 filename (4+2+1=7)

    ​ chmod u =rwx, g=rx, 0=r filename (u-user, g-group, o-others)

    ​ chmod a+x filename 增长权限

​ a-x 减小权限

6. 计算机网络应用层和运输层

应用层

应用层就定义了位于不一样主机中的多个应用进程之间通讯的协议。应用层的许多协议都是基于客户-服务器模式,客户是服务的请求方,服务器是服务提供方。

HTTP非持续链接和持续链接

  • 非持续链接

    定义:每一个请求/相应对是结果一个单独的TCP链接发送

    咱们看看在非持续链接状况下,从服务器向客户传送一个Web页面的步骤。假设该页面含有一个HTML基本文件和10个JPEG图形,而且这11个对象位于同一台服务器上。该HTML文件的URL为:http://www.someSchool.edu/someDepartment/home.index。

    咱们看看发生了什么状况:

    • HTTP客户进程在端口号80发起一个到服务器www.someSchool.edu的TCP链接,该端口号是HTTP的默认端口。在客户和服务器上分别有一个套接字与该链接相关联。
    • HTTP客户经它的套接字向该服务器发送一个HTTP请求报文。请求报文中包含了路径名/someDepartment/home.index(后面咱们会详细讨论HTTP报文)。
    • HTTP服务器进程经它的套接字接收该请求报文,从其存储器(RAM或磁盘)中检索出对象www.someSchool.edu/someDepartment/home.index,在一个HTTP响应报文中封装对象,并经过其套接字向客户发送响应报文。
    • HTTP服务器进程通知TCP断开该TCP链接。(可是直到TCP确认客户已经完整地收到响应报文为止,它才会实际中断链接。)
    • HTTP客户接收响应报文,TCP链接关闭。该报文指出封装的对象是一个HTML文件,客户从响应报文中提取出该文件,检查该HTML文件,获得对10个JPEG图形的引用。

    对每一个引用的JPEG图形对象重复前4个步骤。

    往返时间计算:粗略地讲,总的响应时间就是两个RTT加上服务器传输HTML文件的时间。

    img

  • 持续链接

    定义:全部请求及其响应通过相同的TCP链接发送

    非持续链接有一些缺点。首先,必须为每个请求的对象创建和维护一个全新的链接。对于每一个这样的链接,在客户和服务器中都要分配TCP的缓冲区和保持TCP变量,这给Web服务器带来了严重的负担,由于一台Web服务器可能同时服务于数以百计不一样的客户的请求。第二,就像咱们刚描述的那样,每个对象经受两倍RTT的交付时延,即一个RTT用于建立TCP,另外一个RTT用于请求和接收一个对象。

    在采用持续链接的状况下,服务器在发送响应后保持该TCP链接打开。在相同的客户与服务器之间的后续请求和响应报文可以经过相同的链接进行传送。特别是,一个完整的Web页面(上例中的HTML基本文件加上10个图形)能够用单个持续TCP链接进行传送。更有甚者,位于同一台服务器的多个Web页面在从该服务器发送给同一个客户时,能够在单个持续TCP链接上进行。能够一个接一个地发出对对象的这些请求,而没必要等待对未决请求(流水线)的回答。通常来讲,若是一条链接通过必定时间间隔(一个可配置的超时间隔)仍未被使用,HTTP服务器就关闭该链接。HTTP的默认模式是使用带流水线的持续链接。

HTTP报文格式

  • HTTP请求报文

    GET /somedir/page.html HTTP/1.1
    HOST: www.someschool.edu
    Connetion: close
    User-agent: Mozilla/5.0
    Accept-agent: fr
    复制代码
  • HTTP响应报文

    HTTP/1.1 200 OK
    Date: Sat, 31 Dec 2005 23:59:59 GMT
    Content-Type: text/html;charset=ISO-8859-1
    Content-Length: 122
    <html>
    <head>
    <title>Wrox Homepage</title>
    </head>
    <body>
    <!-- body goes here -->
    </body>
    </html>
    复制代码
  • 用户与服务器交互:cookie

    因为HTTP是无状态的,咱们能够使用cookie来对用户进行认证。

    img

    • web缓存器(代理服务器)

      img

      请求过程:

      • 浏览器创建一个到Web缓存器的TCP链接,并向Web缓存器中的对象发送一个HTTP请求。

      • Web缓存器进行检查,看看本地是否存储了该对象副本。若是有,Web缓存器就向客户浏览器用HTTP响应报文返回该对象。

      • 若是Web缓存器中没有该对象,它就打开一个与该对象的初始服务器(如www.someschool.edu)的TCP链接。Web缓存器则在这个缓存器到服务器的TCP链接上发送一个对该对象的HTTP请求。在收到该请求后,初始服务器向该Web缓存器发送具备该对象的HTTP响应。

      • 当Web缓存器接收到该对象时,它在本地存储空间存储一份副本,并向客户的浏览器用HTTP响应报文发送该副本(经过现有的客户浏览器和Web缓存器之间的TCP链接)。

      web缓存器能够大大减小对客户端请求的响应时间

img

时延计算:
由于客户和缓存链接在一个相同的高速局域网上,这样40%的请求将几乎当即会由缓存器获得响应,时延约在10ms之内。然而,剩下的60%的请求仍然要由初始服务器来知足。可是只有60%的被请求对象经过接入链路,在接入链路上的流量强度从1.0减少到0.6。通常而言,在15Mbps链路上,当流量强度小于0.8时对应的时延较小,约为几十毫秒。这个时延与2秒因特网时延相比是微不足道的。考虑这些以后,平均时延所以为0.4×(0.010秒)+0.6×(2.01秒)&emsp;图2-13&emsp;为机构网络添加一台缓存器这略大于1.2秒。
复制代码
  • FTP相关 一些较为常见的命令以下:

    • USER username:用于向服务器传送用户标识。
    • PASS password:用于向服务器发送用户口令。
    • LIST:用于请求服务器回送当前远程目录中的全部文件列表。该文件列表是经一个(新建且非持续链接)数据链接传送的,而不是在控制TCP链接上传送。
    • RETR filename:用于从远程主机当前目录检索(即get)文件。该命令引发远程主机发起一个数据链接,并经该数据链接发送所请求的文件。
    • STOR filename:用于在远程主机的当前目录上存放(即put)文件。

    一些典型的回答连同它们可能的报文以下所示:

    • 331 Username OK,Password required(用户名OK,须要口令)。
    • 125 Data connection already open;transfer starting(数据链接已经打开,开始传送)。
    • 425 Can’t open data connection(没法打开数据链接)。
    • 452 Error writing file(写文件差错)。
  • DNS相关

    • DNS层次结构

      img

    + 各类DNS服务器交互

img

img

  • 递归查询

​ 递归查询是一种DNS 服务器的查询模式,在该模式下DNS 服务器接收到客户机请求,必须使用一个准确的查询结果回复客户机。若是DNS 服务器本地没有存储查询DNS 信息,那么该服务器会询问其余服务器,并将返回的查询结果提交给客户机。

客户机和服务器之间的查询是递归查询

​ 是递归查询告诉客户机IP

  • 迭代查询

​ DNS 服务器另一种查询方式为迭代查询,DNS 服务器会向客户机提供其余可以解析查询请求的DNS 服务器地址,当客户机发送查询请求时,DNS 服务器并不直接回复查询结果,而是告诉客户机另外一台DNS 服务器地址,客户机再向这台DNS 服务器提交请求,依次循环直到返回查询的结果为止。

服务器之间的查询是迭代查询

img

  • DNS缓存

    DNS服务器在一段时间后(一般设置为两天)将丢弃缓存的信息。

运输层

  • 多路复用和分解

    ​ 将运输层报文段中的数据交付到正确的套接字的工做称为多路分解(demultiplexing),在源主机当中从不一样的套接字中收集数据块,并为每个数据块封装上首部信息(用于分解)从而生成报文段,而后将此报文段传递到网络层。全部的这些工做称为多路复用(multiplexing)

    运输层多路复用的要求:

    套接字有惟一的标识符; 每个报文段有特殊的字段来指示该报文段所要交付到的套接字。(这些特殊的字段是源端口字段和目的端口字段,端口号是一个16bit的数范围是0-65535.其中0-1023是周知端口)。

    TCP的首部开销为20个字节,而UDP的首部开销为8字节 无链接的多路复用与多路分解(UDP)

    一个UDP套接字是由一个二元组来全面标志的,该二元组包含一个目的IP地址和一个目的端口号,所以若是两个UDP报文段有不一样的源IP地址和/或源端口号,可是具备相同的目的IP地址和目的端口号,那么这两个报文段将经过相同的套接字被定向到相同的进程。

    UDP报文格式:

UDP报文格式

​ 长度字段:指示了在UDP报文段中的字节数(首部加数据,以字节为单位) ​ 检验和:接收方使用检验和来检查在该报文段中是否出现差错

​ UDP虽然实现了检验和,可是对恢复差错无能为力,要么它丢弃受损的报文段,要么将受损的报文段交给应用程序并给出警告。

面向链接的多路复用和多路分解(TCP)

​ TCP套接字和UDP套接字的细微的差异是,TCP套接字是由一个四元组(源IP地址,源端口号,目的IP地址,目的端口号)来标识的。这样当一个TCP报文段从网络到达另一台主机时,该主机使用所有的4个值来将报文段定向(分解)到相应的套接字。特别与UDP不一样的是,两个具备不一样的IP地址的或者是源端口号的到达TCP报文段将被定向到两个不一样的套接字,除非TCP报文段携带了初始建立链接的请求 。服务器主机能够支持不少并行的TCP套接字,每个套接字和一个进程相联系,并由其四元组来标识每个套接字。当一个TCP报文段到达主机时,全部的四个字段(源IP、源端口、目的IP、目的端口)被用来将报文段定向(分解)到相应的套接字。 ​ TCP链接老是点对点的,所谓的“多播”,即在一次的发送操做当中从一个发送方将数据传输给多个接收方,对于TCP来讲是不可能的。

4位首部长度:指示TCP头部大小(以32bit为单位),指示何处数据开始,因为TCP选项的缘由,TCP首部长度是可变的。(可是一般选项为空,TCP头部典型长度为20字节,因此首部长度一般为5,即1001). 16位窗口大小:用来表示想要收到的每一个TCP数据段的大小。TCP的流量控制由链接的每一端经过声明窗口的大小来提供。窗口的大小为字节数,起始于确认序号字段指明的值,这个值是接收端正指望接收到的字节。窗口的大小是一个16字节字段,于是窗口大小最大为65535字节。 16位检验和:16位TCP头部检验和。源主机基于数据内容计算一个数值,目的主机要和源主机计算的结果一致,从而验证数据的有效性。检验和覆盖的是整个的TCP报文段:这是一个强制性的字段,必定是由发送端计算和存储,并由接收端进行验证。

URG:紧急标志,为1时表示有效,紧急数据的最后一个字节由16bit的紧急数据指针字段指出。当紧急数据存在时,

ACK:确认标志。代表确认编号栏有效,大多数状况下该标识位是置位的。TCP报头内的确认编号栏内包含的确认编号(W+1)为下一个预期接收到的序列编号,同时提示远端系统已经成功的接收到了全部数据。

PSH:推标志。该标志置位时,接收端不将该数据进行队列处理,而是尽量快地将数据转由应用处理(接收方当即将数据交给上层)。在处理Telnet或rlogin等交互模式的链接时,该标志老是置位的。

RST:复位标志。用于复位(重置)相应的TCP链接。

SYN:同步标志。代表同步序列编号栏有效。该标志仅在三次握手创建TCP链接时有效。它提示TCP链接的服务端检查序列编号,该序列编号为TCP链接初始端(通常是客户端)的初始序列编号。

FIN:结束标志。

TCP三次握手创建链接

三次握手(Three-Way Handshake)即创建TCP链接时,须要客户端和服务端总共发送3个包确认链接的创建。在socket编程中,这一过程由客户端执行connect()来触发。流程以下:

TCP三次握手

TCP三次握手

第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。

第二次握手:Server收到数据包后由标志位SYN=1知道Client请求创建链接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认链接请求,Server进入SYN_RCVD状态。 第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,若是正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,若是正确则链接创建成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间能够开始传输数据了。(前两次握手是是不承载"有效载荷"的,而第三次握手是能够承载"有效载荷"的。)

其中有一个半链接状态:服务器维护一个半链接队列,该队列为每一个客户端SYN包开设一个条目,标明服务器已经接到SYN包,并向客户端发出确认,这些条目表示的链接处于SYN_RECV状态,获得客户端的确认后进入ESTABLISHED状态。

TCP四次挥手断开链接

四次挥手(Four-Way Wavehand)是指断开一个TCP链接时须要客户端和服务器总共发送四个包以确认链接的断开。在socket()编程中,这一个过程由客户端或者服务器端的任意一方执行close来触发。整个流程图以下:

TCP四次挥手

第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。

第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。

第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。

第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

连接:http://www.jianshu.com/p/37d132327724

  • TCP拥塞控制机制

    ​ 拥塞控制(congestion control)是TCP协议的一项重要功能,TCP的拥塞控制机制是从端到端的角度,推测网络是否发生拥塞,若是推断网络发生拥塞,则当即将数据发送速率降下来,以便缓解网络拥塞。 ​ TCP的拥塞控制采用的是窗口机制,经过调节窗口的大小实现对数据发送速率的调整。TCP的发送端维持一个称为拥塞窗口cwnd的变量,单位为字节,用于表示在未收到接收端确认的状况下,能够连续发送的数据字节数。cwnd的大小取决于网络的拥塞程度,而且动态地发生变化。拥塞窗口调整的原则是:只要网络没有出现拥塞,就能够增大拥塞窗口,以便将更多的数据发送出去,至关于提升发送速率;一旦网络出现拥塞,拥塞窗口就减少一些,减小注入网络的数据量,从而缓解网络的拥塞。 ​ 发送端判断网络发生拥塞的依据是:发送端设置一个重传计时器RTO,对于某个已发出的数据报文段,若是在RTO计时到期后,尚未收到来自接收端的确认,则认为此时网络发生了拥塞。 TCP的拥塞控制算法包括了慢启动(slow start)、拥塞避免(congestion avoidance)、快速重传(fast retransmit)和快速恢复(fast recovery)四部分。 ​ 慢启动算法做用在TCP数据传输的开始阶段,当主机开始发送数据时,由于不知道网络中的负荷状况,若是当即发送大量的数据,有可能会引发网络的拥塞。所以,TCP采用试探的方法,逐渐增大拥塞窗口。一般在刚开始发送数据报文段时,先将拥塞窗口cwnd设置为一个TCP最大段长度MSS的值。而在每收到一个数据报文段的确认后,cwnd就增长一个MSS的数值。这样就能够逐渐增大发送端的拥塞窗口,使数据注入网络的速率比较合理。若是定义从发送端发出一个数据报文段到收到这个数据报文段的确认的时间间隔为往返时间RTT,则在慢启动阶段,每通过一个RTT,cwnd的值就加倍。 ​ 为了防止拥塞窗口增加过快而引发网络拥塞,TCP还须要设置一个慢启动阈值ssthresh,当拥塞窗口的值增长到ssthresh时,就要减缓拥塞窗口的增加速度,具体的作法是每通过一个RTT,拥塞窗口cwnd的值加1(单位为MSS),这样就能够使cwnd按线性规律缓慢增加,这个过程称之为“加性增长”(Additive Increase)算法。一般状况下,拥塞窗口cwnd的初值被设置为1,慢启动阈值ssthresh的初值被设置为16。当拥塞避免算法执行到某个时刻,发送端在规定时间内没有收到接收端的确认,即发生了网络超时,则意味着网络发生了拥塞。此时,发送端首先将ssthresh的值变为发生超时时cwnd值的一半,同时将cwnd的值置为1,从新执行慢启动算法。这样作的好处是,当网络频繁出现拥塞时,ssthresh降低得很快,能够大大减小注入网络中的数据报文段。一般称这个过程为“乘性减少”(MultiplicativeDecrease)算法。TCP中的“加性增长”和“乘性减少”算法合起来称为AIMD算法。 ​ 慢启动和拥塞避免是1988年提出的拥塞控制算法,1990年在此基础上又增长了快速重传和快速恢复两个算法。 快速重传算法的基本思想是:接收端每收到一个失序的数据报文段后就当即发出重复确认,以便更早地通知发送端有丢包的状况发生。假设在某个TCP数据传输过程当中,接收端依次收到发送端发出的1号和2号数据报文段,并对这两个数据报文段发送确认后,没有按次序收到3号数据报文段,而是收到了4号,这时就须要当即向发送端发送一个2号数据报文段的确认,称为重复确认。同理,若是继续收到5号、6号数据报文段,接收端仍然要向发送端发出2号数据报文段的重复确认。此时,发送端会收到多个2号数据报文段的重复确认,则认为3号数据报文段发生了丢包,须要当即向接收端重传3号数据报文段,而不须要等待重传计时器到期再重传。快速重传算法中规定若是收到某数据报文段的三个重复确认,则当即重传下一个数据报文段。 ​ 快速恢复是配合快速重传使用的算法,其基本思想是:当发送端连续收到三个重复确认时,就将慢启动阈值ssthresh减半,以预防网络拥塞的发生,而且将拥塞窗口cwnd的值置为减半后的ssthresh,而后开始执行拥塞避免算法,使得cwnd缓慢地加性增大。

    TCP拥塞控制算法描述以下:

    SlowStartPhase( )   //慢启动算法
    {
      CongWin=1;  //拥塞窗口cwnd的初值为1个MSS
      while (CongWin<Threshold&& 无数据丢失) 
     //当拥塞窗口小于慢启动阈值且没有发生丢包时
      {
      for each ACK
    CongWin++;    //每收到一个确认数据报,拥塞窗口加1
      }
      if (CongWin>=Threshold) then
      CongestionAvoidancePhase( );
     //当拥塞窗口大于等于慢启动阈值时,启动拥塞避免算法;
      if (数据丢失) then
      DataLoss( );   // 丢包后的处理方法
    }
    CongestionAvoidancePhase( )    // 拥塞避免算法
    {
      while (无数据丢失)
      {
      for each RTT
    CongWin=CongWin+1;     //每通过一个RTT,拥塞窗口加1
      }
      DataLoss( );
    }
    DataLoss( )    //丢包后的处理方法
    {
      if (超时) then
      {
    Threshold=CongWin/2;
      CongWin=1;
      SlowStartPhase( );
     //若是发生超时,慢启动阈值置为当前拥塞窗口的一半,而后将拥塞窗口置1,开始执行拥塞避免算法。
      }
      if (3次重复确认) then
      {
    Threshold=CongWin/2;
          CongWin=CongWin/2;
          CongestionAvoidancePhase();
    //若是收到3个重复的确认,则执行快速重传和快速恢复算法,慢启动阈值减少为拥塞窗口的一半,同时将拥塞窗口减半,开始拥塞避免算法
    复制代码

    连接:http://www.jianshu.com/p/7d59f9292b03

7.网络安全方面

  1. SQL注入

示例:

sql_login = "SELECT COUNT(*) FROM login WHERE userName= %s AND password=%s" %(userName, password)

此时若 username = 'admin--' 则不论password为何都能登陆

解决方案:sql_login = "SELECT COUNT(*) FROM login WHERE userName= %s AND password=%s"

values = (username, password)

cur.execute(sql_login, values)

学习简单SQL注入:

  • AND

    and 1=1 and 1=2

    • 猜表

      and 0 < (select count(*) from admin) ---判断是否存在admin这张表

    • 此类相似,经过使用 and来达到本身的查询目的

  • ; ;结束以前的SQL语句

  • -- 忽略后面的语句

  • OR 使前面的判断失效 解决方案: 绑定变量使用预编译语句是预防SQL注入的最佳方式,使用预编译的SQL语句语义不会发生改变,在SQL语句中,变量用问号?表示,黑客即便本事再大,也没法改变SQL语句的结构,像上面例子中,username变量传递的plhwin' AND 1=1-- hack参数,也只会看成username字符串来解释查询,从根本上杜绝了SQL注入攻击的发生。

  1. DDOS攻击

DDOS的表现形式主要有两种,一种为流量攻击,主要是针对网络带宽的攻击,即大量攻击包致使网络带宽被阻塞,合法网络包被虚假的攻击包淹没而没法到达主机;另外一种为资源耗尽攻击,主要是针对服务器主机的攻击,即经过大量攻击包致使主机的内存被耗尽或CPU被内核及应用程序占完而形成没法提供网络服务。

  1. xss攻击 示例:
@main_view.route('/test')
def test():
    test_data = "zhaonan=guest<script>alert('attacked')</script>"
    return ''' <html> <head> <title>Home Page</title> </head> <body> <h1>Hello, ''' + test_data + '''</h1> </body> </html> '''
复制代码

在网站上输入 localhost/test以后会显示一个attacked的弹窗

  1. CSRF攻击

参考网站:http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html

img

防护:服务端的CSRF方式方法不少样,但总的思想都是一致的,就是在客户端页面增长伪随机数。

  • Cookie Hashing(全部表单都包含同一个伪随机值):

  这多是最简单的解决方案了,由于攻击者不能得到第三方的Cookie(理论上),因此表单中的数据也就构造失败了:>

  这个方法我的以为已经能够杜绝99%的CSRF攻击了,那还有1%呢....因为用户的Cookie很容易因为网站的XSS漏洞而被盗取,这就另外的1%。通常的攻击者看到有须要算Hash值,基本都会放弃了,某些除外,因此若是须要100%的杜绝,这个不是最好的方法。

  • 验证码

  这个方案的思路是:每次的用户提交都须要用户在表单中填写一个图片上的随机字符串,厄....这个方案能够彻底解决CSRF,但我的以为在易用性方面彷佛不是太好,还有听闻是验证码图片的使用涉及了一个被称为MHTML的Bug,可能在某些版本的微软IE中受影响。

+ One-Time Tokens(不一样的表单包含一个不一样的伪随机值)

  在实现One-Time Tokens时,须要注意一点:就是“并行会话的兼容”。若是用户在一个站点上同时打开了两个不一样的表单,CSRF保护措施不该该影响到他对任何表单的提交。考虑一下若是每次表单被装入时站点生成一个伪随机值来覆盖之前的伪随机值将会发生什么状况:用户只能成功地提交他最后打开的表单,由于全部其余的表单都含有非法的伪随机值。必须当心操做以确保CSRF保护措施不会影响选项卡式的浏览或者利用多个浏览器窗口浏览一个站点。

8. SQL反模式

  • 乱穿马路

    目标:存储多值属性

    反模式:格式化的逗号分隔列表

    坏处

    • 索引显然是不能用了
    • 增长了查询的难度,这里的难度是说sql语句更难写了,只有及其少数的操做优化了,是哪一个操做就显而易见了。
    • 列表的长度有限制,好比varchar的字段长度是有限的。

    解决方案:建立一张交叉表

    示例

    一个产品可能有多个联系人。 能够这样设计:

    CREATE TABLE Contacts (
      product_id BIGINT UNSIGNED NOT NULL,
      account_id BIGINT UNSIGNED NOT NULL ,
      PRIMARY KEY (product_id,account_id),
      FOREIGN KEY (product_id) REFERENCES Products(product_id),
      FOREIGN KEY (account_id) REFERENCES Accounts(account_id)
    );
    复制代码

    好处

    • 能够添加索引
    • 能够添加额外的信息,好比一些操做时间等
    • 主要联系人和次要联系人等均可以实现
  • 单纯的树

    ​ 在树形结构中,实例被称为节点。每一个节点都有多个子节点与一个父节点。

    ​ 最上层的节点叫作**根(root)节点,**它没有父节点。

    ​ 最底层的没有子节点的节点叫作叶(leaf)

    ​ 中间的节点简单地称为非叶节点(nonleaf)

    **目标:**分层存储与查询,好比:系统字典、组织机构、省份区域等树形结构数据或者以层级方式组织的数据。

    **反模式:**老是依赖父节点(使用邻接表)。

    ​ 最简单的实现方式是添加ParentId字段,引用同一张表的主键ID。

    ​ 邻接表维护树比较方便,可是查询很笨拙,若是要找一个节点下的全部子节点,要关联不少次,这个关联次数取决于树的深度,

    ​ 因此,邻接表不能用于存储比较深的树。

    **如何识别反模式:**当出现如下状况时,多是反模式

    ​ (1)咱们的数结构要支持多少层

    ​ (2)咱们老是很惧怕接触那些管理树结构的代码

       (3)我须要一个脚原本按期的清理树中的孤立节点数据

    **解决方案:**使用其余树模型

    • 路径枚举:

        用一个path字段保存当前节点的最顶层的祖先到本身的序列(路径)

    选区_002

        优势:查询方便;

        缺点:一、不能保证存储的值的有效性。

    ​ 二、增、删时,要考虑对原位置下的子节点如何处理,比较麻烦。

    ​ 三、若是还要维护一个排序path,那就更麻烦了。

    • 嵌套集:

        存储子孙节点的相关信息,而不是节点的直接祖先。用nsleft存储全部后台的nsleft中最小的数-1,

    ​ 用nsright存储全部后台的nsright中最大的数+1。

    CREATE TABLE Comments (
    comment_id
    SERIAL PRIMARY KEY,
    nsleft
    INTEGER NOT NULL,
    nsright
    INTEGER NOT NULL,
    bug_id
    BIGINT UNSIGNED NOT NULL,
    author
    BIGINT UNSIGNED NOT NULL,
    comment_date DATETIME NOT NULL,
    comment
    TEXT NOT NULL,
    FOREIGN KEY (bug_id) REFERENCES Bugs (bug_id),
    FOREIGN KEY (author) REFERENCES Accounts(account_id)
    );
    复制代码

        优势:删除时,原来子节点的关系自动上移。

        缺点:一、查询一个节点的直接上级或下级,很困难。

    ​ 二、增、删,困难。

    • 闭包:记录了树中全部节点间的关系,而不只仅是只有那些直接的父子关系。

    ​ 将树中任何具备**“祖先-后代”关系的节点对**都存储在TreePath表中的一行,同时增长一行指向节点本身。

    CREATE TABLE Comments (
    comment_id
    SERIAL PRIMARY KEY,
    bug_id
    BIGINT UNSIGNED NOT NULL,
    author
    BIGINT UNSIGNED NOT NULL,
    comment_date DATETIME NOT NULL,
    comment
    TEXT NOT NULL,
    FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
    FOREIGN KEY (author) REFERENCES Accounts(account_id)
    );
    CREATE TABLE TreePaths (
    ancestor
    BIGINT UNSIGNED NOT NULL,
    descendant BIGINT UNSIGNED NOT NULL,
    PRIMARY KEY(ancestor, descendant),
    FOREIGN KEY (ancestor) REFERENCES Comments(comment_id),
    FOREIGN KEY (descendant) REFERENCES Comments(comment_id)
    );
    复制代码

    ​ 优势:一、能快速的查询给定节点的祖先与后代;

    ​ 二、能更加简单的维护分层信息;

    ​ 三、若是删除了TreePath表中的一条记录,那么并非真正的删除具体信息表中的记录。这样设计有时候颇有用:

    好比在产品目录的分类或者员工组织架构的图标中,当你改变了节点关系的时候,并非真的想要删除一个节点。

    ​ 咱们把关系路径存储在一个分开独立的表中,使得设计更加灵活。

    ​ 缺点:查询直接父节点或子节点,须要在表中增长Path_Length字段来维护。

    结论:

    ​ 每种设计各有优劣,如何选择设计依赖于应用程序中的哪一种操做最须要性能上的优化。

    ​ 邻接表:简单,但不适用于很深的表;

       枚举路径:没法保证引用完整性;

       嵌套集:没法保证引用完整性,太复杂;

       闭包:须要一个额外的表存储关系;

  • 须要ID

    目标:创建主键规范

    反模式:以不变应万变,即每一个数据库中的表都须要一个伪主键Id

    ​ 在表中,须要引入一个对于表的域模型无心义的新列来存储一个伪值,这一列被用做这张表的主键,从而经过它来肯定表中的一条记录,即使其余的列容许出现适当的重复项。这种类型的主键列咱们一般称其为“伪主键”或者“代理键”。

    1. 冗余键值:若是存在一个逻辑上更为天然的主键而且也知足unique约束,那么id就多余了;
    2. 容许重复项:伪主键自己确保了表的数据不会存在重复项,因此也就没法避免表中的其它数据出现重复项;
    3. 意义不明的关键字:主键名应该便于理解,因此建议用XxxId,而不都是用Id;
    4. 使用组合键。

    **如何识别反模式:**当出现如下状况时,多是反模式

    1. 我以为这张表不须要主键;
    2. 我怎么能在多对多的表中存储重复的项;
    3. 我学过《数据库设计理论》,里面说我应该把数据移动到一张查询表中,而后经过ID查找。可是我不想这么作,由于每次我想要得到真是的数据,都不得不作一次链接查询。(这在数据库设计中是一个常见的误区,称为“正规化”,然而实际中对于伪主键并无什么须要作的)

    解决方案:

    1. 直接了当的描述设计,主键名应该便于理解,因此建议用XxxId,而不都是用Id;

    2. 拥抱天然键和组合键。

  • 不用钥匙的入口(外键约束)

    **目标:**简化数据库架构

    **反模式:**无视约束,即不使用约束

    **如何识别反模式:**当出现如下状况时,多是反模式

    ​ 一、我要怎么写这个查询来检查一个值是否没有被同时存在2张表中?

    ​ (一般这样的需求是为了查找那些孤立的行数据)

    ​ 二、有没有一种简单的方法来判断在一张表中的数据是否也在第二张表中存在?

    ​ (这么作是用来确认父记录切实存在。外键会自动完成这些,而且外键会使用这父表的索引尽量的高效完成)

    ​ 三、有人说不要用外键,外键影响数据库效率。

    **解决方案:**声明约束

    ​ 一、经过使用外键来确保应用完整性;

    ​ 使用约束时:

    ​ (1)数据库自己会拒绝全部不合理的改变,不管这个改变是经过什么方式形成的。

    ​ (2)可以避免编写没必要要的代码,同时还能确保一旦修改了数据库中的内容,全部的代码依旧可以用一样的方式执行。

    ​ (3)外键的特性:级联更新,好比:On Update Cascade、On Delete Restrict等。 在执行更新和删除2个操做中的任意1个是,数据库都会自动修改多张表中的数据, 外键的引用状态在操做以前和以后都保持无缺。

    ​ 二、外键约束的确须要多那么一点额外的系统开销,但相比于其余的一些选择,外键确实更高效一点:

    ​ (1)不须要在更新或删除记录前执行Select检查;

    ​ (2)在同步修改时不须要再锁住整张表;

    ​ (3)再也不须要执行按期监控脚原本修正不可避免的孤立数据。

  • 实体-属性-值

    **目标:**支持可变属性

    **反模式:**使用泛型属性表。这种设计成为实体-属性-值(EAV),也可叫作开放架构、名-值对。

    ​ 优势:经过增长一张额外的表,能够有如下好处

    ​ (1)表中的列不多;

    ​ (2)新增属性时,不须要新增列。不会影响现有表的结构;

    ​ (3)存储的字段内容不会为空值。

    ​ 缺点:(1)查询语句变得更加复杂;

    ​ (2)使用EAV设计后,须要放弃传统的数据库设计所带来的方便之处,好比:没法保障数据完整性;

    ​ (3)没法使用SQL的数据类型,好比对日期、金钱等格式内容都只能保持为字符串类型;

    ​ (4)没法确保引用完整性;

    ​ (5)没法配置属性名。好比,有可能表中存在两条记录,

    ​ 一条的attr_name是sex,一条attr_name是gender,都是表示性别;

    ​ (6)查询结果中有多个属性时,查询很是困难,且查询性能没法控制。

    **如何识别反模式:**当出现如下状况时,多是反模式

      (1)数据库不须要修改元数据库(表中的列属性)就能够扩展。还能够在运行时定义新的属性。

      (2)查询是链接数量很是多,且链接的数量可能会达到数据库的限制时,你的数据库的设计多是有问题的。

      (3)普通的报表查询变的及其复杂甚至不且实际。

    **解决方案:**模型化子类型

      一、单表继承:全部属性都在一个单表上保存,增长属性时就扩充这个表。

    ​ 缺点:

    ​ (1)当程序须要加入新对象时,必须修改数据库来适应这些新对象。又因为这些新对象具备一些和老对象 不用的属性, 于是必须在原有表里增长新的属性列,可能会遇到一个实际的问题,就是每张表的列的数量是有限制的。

    ​ (2)没有任何的元信息来记录哪一个属性属于哪一个子类型。

    ​ 当数据的子类型不多,以及子类型特殊属性不多,就能够使用单表继承。

      二、实体表继承:为每一个子类型建立一张独立的表,每一个表包含哪些属于基类的共有属性,同时也包含了子类型特殊化的属性。

​ 优势:

​ (1)实体继承类设计相比于但表继承设计的优点在于提供了一种方法, 让你能组织在一行内存储一些和当前子类型无关的属性。若是你引用一个并不存在于这张表中的属性列,数据库会自动提示你错误。

​ (2)不用像在单表继承设计里那样使用额外的属性来标记子类型。

​ 缺点:很难将通用属性和子类特有属性区分开来。所以,若是将一个新的属性增长到通用属性中,必须为每一个子类表都添加一遍。

​ 当你不多须要一次性查询多有子类型时,实体继承表设计是最好的选择。

  三、类表继承:把表当成面向对象里的类。

​ 建立一张基类表,包含全部子类型的公共属性。对于每一个子类型,建立一个独立的表,经过外键和基类表相连。

  四、半结构化数据模型:若是有不少子类型或者必须常常增长新的属性支持,那么能够用一个BLOB列来存储数据,用XML或者JSON格式——同事包含了属性的名字和值。这叫作序列化大对象块。

   这个设计的优点是扩展性,缺点是,这样的结构中sql没法获取某个指定的属性。你必须或者整个blob字段并经过程序去解释这些属性。

   当你须要绝对的灵活性时,能够使用这个方案。

​ 若是使用了EAV,那么能够先将所有属性取出,而后再作其余处理。

  • 多态关联

  • 多列属性

  • 元数据分裂

9. 数据库设计的三范式

  • 1NF:无重复的列,即每一列都是不可分割的基本数据项

商品表 goods:

id price color
1 10 red
2 20 blue
3 30 red, blue

能够拆分为两个表,价格表和颜色表: 价格表 goods_price:

id price
1 10
2 20
3 30

颜色表 goods_color

id color
1 red
2 blue
3 red
3 blue
  • 2NF:属性彻底依赖于主键 以下表所示:学分依赖于课程,不依赖于主键学号 考试成绩表 exam:

    学号 姓名 课程 学分 成绩
    1 Tom 数学 4 80
    2 Kate 数学 4 90

能够拆分为三个表,学生信息表,课程表和考试成绩表:

学生信息表 student:

学号 姓名
1 Tom
2 Kate

课程表 course:

课程编号 课程名 学分
101 数学 4
102 语文 2

考试成绩表 exam:

学号 课程编号 成绩
1 101 80
2 101 90
  • 3NF:属性不依赖于其余非主属性,即不能有冗余

    以下表所示:班主任手机依赖于班主任姓名 这个非主属性

学生信息表 student:

学号 姓名 班主任姓名 班主任手机
1 Tom Lily 138
2 Kate Lily 138

能够拆分为两个表,学生信息表,班主任信息表:

学生信息表 student:

学号 姓名 班主任姓名
1 Tom Lily
2 Kate Lily

班主任信息表 teacher:

班主任姓名 班主任手机
Lily 138
Cat 139

连接:http://www.jianshu.com/p/841573f02f8e

相关文章
相关标签/搜索