@@ -454,6 +454,42 @@ d = [1, 2, 3, 4, ['a', 'b']]
454
454
455
455
## 24 Python垃圾回收机制
456
456
457
+ Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率。
458
+
459
+ ### 1 引用计数
460
+
461
+ PyObject是每个对象必有的内容,其中` ob_refcnt ` 就是做为引用计数。当一个对象有新的引用时,它的` ob_refcnt ` 就会增加,当引用它的对象被删除,它的` ob_refcnt ` 就会减少.引用计数为0时,该对象生命就结束了。
462
+
463
+ 优点:
464
+
465
+ 1 . 简单
466
+ 2 . 实时性
467
+
468
+ 缺点:
469
+
470
+ 1 . 维护引用计数消耗资源
471
+ 2 . 循环引用
472
+
473
+ ### 2 标记-清除机制
474
+
475
+ 基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放。
476
+
477
+ ### 3 分代技术
478
+
479
+ 分代回收的整体思想是:将系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量。
480
+
481
+ Python默认定义了三代对象集合,索引数越大,对象存活时间越长。
482
+
483
+ 举例:
484
+ 当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,而对集合A进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。
485
+
486
+ ## 25 Python的List
487
+
488
+ 推荐: http://www.jianshu.com/p/J4U6rR
489
+
490
+ ## 26 Python的is
491
+
492
+
457
493
# 操作系统
458
494
459
495
## 1 select,poll和epoll
@@ -474,6 +510,110 @@ poll改善了第一个缺点
474
510
475
511
epoll改了三个缺点.
476
512
513
+ 关于epoll的: http://www.cnblogs.com/my_life/articles/3968782.html
514
+
515
+ ## 2 调度算法
516
+
517
+ 1 . 先来先服务
518
+ 2 . 短作业优先
519
+ 3 . 最高优先权调度
520
+ 1 . 时间片轮转
521
+ 2 . 多级反馈队列调度
522
+
523
+ 实时调度算法:
524
+
525
+ 1 . 最早截至时间优先 EDF
526
+ 2 . 最低松弛度优先 LLF
527
+
528
+ ## 3 死锁
529
+ 原因:
530
+
531
+ 1 . 竞争资源
532
+ 2 . 程序推进顺序不当
533
+
534
+ 必要条件:
535
+
536
+ 1 . 互斥条件
537
+ 2 . 请求和保持条件
538
+ 3 . 不剥夺条件
539
+ 4 . 环路等待条件
540
+
541
+ 处理死锁基本方法:
542
+
543
+ 1 . 预防死锁(摒弃除1以外的条件)
544
+ 2 . 避免死锁(银行家算法)
545
+ 3 . 检测死锁(资源分配图)
546
+ 4 . 解除死锁
547
+ 1 . 剥夺资源
548
+ 2 . 撤销进程
549
+
550
+
551
+ ## 4 程序编译与链接
552
+
553
+ 推荐: http://www.ruanyifeng.com/blog/2014/11/compiler.html
554
+
555
+ Bulid过程可以分解为4个步骤:预处理(Prepressing), 编译(Compilation)、汇编(Assembly)、链接(Linking)
556
+
557
+ 以c语言为例:
558
+
559
+ ### 1 预处理
560
+
561
+ 预编译过程主要处理那些源文件中的以“#”开始的预编译指令,主要处理规则有:
562
+
563
+ 1 . 将所有的“#define”删除,并展开所用的宏定义
564
+ 2 . 处理所有条件预编译指令,比如“#if”、“#ifdef”、 “#elif”、“#endif”
565
+ 3 . 处理“#include”预编译指令,将被包含的文件插入到该编译指令的位置,注:此过程是递归进行的
566
+ 4 . 删除所有注释
567
+ 5 . 添加行号和文件名标识,以便于编译时编译器产生调试用的行号信息以及用于编译时产生编译错误或警告时可显示行号
568
+ 6 . 保留所有的#pragma编译器指令。
569
+
570
+ ### 2 编译
571
+
572
+ 编译过程就是把预处理完的文件进行一系列的词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。这个过程是整个程序构建的核心部分。
573
+
574
+ ### 3 汇编
575
+
576
+ 汇编器是将汇编代码转化成机器可以执行的指令,每一条汇编语句几乎都是一条机器指令。经过编译、链接、汇编输出的文件成为目标文件(Object File)
577
+
578
+ ### 4 链接
579
+
580
+ 链接的主要内容就是把各个模块直接爱你相互引用的部分处理好,使各个模块可以正确的拼接。
581
+ 链接的主要过程包块 地址和空间的分配(Address and Storage Allocation)、符号决议(Symbol Resolution)和重定位(Relocation)等步骤。
582
+
583
+ ## 5 静态链接和动态链接
584
+
585
+ 静态链接方法:静态链接的时候,载入代码就会把程序会用到的动态代码或动态代码的地址确定下来
586
+ 静态库的链接可以使用静态链接,动态链接库也可以使用这种方法链接导入库
587
+
588
+ 动态链接方法:使用这种方式的程序并不在一开始就完成动态链接,而是直到真正调用动态库代码时,载入程序才计算(被调用的那部分)动态代码的逻辑地址,然后等到某个时候,程序又需要调用另外某块动态代码时,载入程序又去计算这部分代码的逻辑地址,所以,这种方式使程序初始化时间较短,但运行期间的性能比不上静态链接的程序
589
+
590
+ ## 6 虚拟内存技术
591
+
592
+ 虚拟存储器是值具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储系统.
593
+
594
+ ## 7 分页和分段
595
+
596
+ 分页: 用户程序的地址空间被划分成若干固定大小的区域,称为“页”,相应地,内存空间分成若干个物理块,页和块的大小相等。可将用户程序的任一页放在内存的任一块中,实现了离散分配。
597
+
598
+ 分段: 将用户程序地址空间分成若干个大小不等的段,每段可以定义一组相对完整的逻辑信息。存储分配时,以段为单位,段与段在内存中可以不相邻接,也实现了离散分配。
599
+
600
+ ### 分页与分段的主要区别
601
+
602
+ 1 . 页是信息的物理单位,分页是为了实现非连续分配,以便解决内存碎片问题,或者说分页是由于系统管理的需要.段是信息的逻辑单位,它含有一组意义相对完整的信息,分段的目的是为了更好地实现共享,满足用户的需要.
603
+ 2 . 页的大小固定,由系统确定,将逻辑地址划分为页号和页内地址是由机器硬件实现的.而段的长度却不固定,决定于用户所编写的程序,通常由编译程序在对源程序进行编译时根据信息的性质来划分.
604
+ 3 . 分页的作业地址空间是一维的.分段的地址空间是二维的.
605
+
606
+ ## 8 页面置换算法
607
+
608
+ 1 . 最佳置换算法OPT:不可能实现
609
+ 2 . 先进先出FIFO
610
+ 3 . 最近最久未使用算法LRU:最近一段时间里最久没有使用过的页面予以置换.
611
+ 4 . clock算法
612
+
613
+ ## 9 边沿触发和水平触发
614
+
615
+ 边缘触发是指每当状态变化时发生一个 io 事件,条件触发是只要满足条件就发生一个 io 事件
616
+
477
617
# 数据库
478
618
479
619
## 1 事务
@@ -483,6 +623,11 @@ epoll改了三个缺点.
483
623
## 2 数据库索引
484
624
485
625
626
+
627
+ ## 3 Redis原理
628
+
629
+
630
+
486
631
# 网络
487
632
488
633
## 1 三次握手
@@ -514,9 +659,9 @@ epoll改了三个缺点.
514
659
3 . MD5+Salt方式,这个salt可以随机
515
660
4 . 知乎使用了Bcrypy(好像)加密
516
661
517
- ## 9 HTTPs
662
+ ## 9 HTTPS
518
663
519
- 对称加密,非对称加密,TLS/SSL,RSA
664
+ HTTPS握手, 对称加密,非对称加密,TLS/SSL,RSA
520
665
521
666
## 10 XSRF和XSS
522
667
@@ -567,6 +712,9 @@ soapp
567
712
568
713
中间人攻击(Man-in-the-middle attack,通常缩写为MITM)是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。
569
714
715
+ ## 17 c10k问题
716
+
717
+ 所谓c10k问题,指的是服务器同时支持成千上万个客户端的问题,也就是concurrent 10 000 connection(这也是c10k这个名字的由来)。
570
718
# * NIX
571
719
572
720
## unix进程间通信方式(IPC)
@@ -656,8 +804,6 @@ l2 = []
656
804
657
805
` 1->2->3->4 ` 转换成` 2->1->4->3 ` .
658
806
659
-
660
-
661
807
``` python
662
808
# Definition for singly-linked list.
663
809
# class ListNode:
@@ -776,10 +922,88 @@ def node(l1, l2):
776
922
else :
777
923
l1 = l1.next
778
924
l2 = l2.next
779
-
925
+ ```
926
+
927
+ ## 快排
780
928
929
+ ``` python
930
+ def qsort (seq ):
931
+ if seq== []:
932
+ return []
933
+ else :
934
+ pivot= seq[0 ]
935
+ lesser= qsort([x for x in seq[1 :] if x< pivot])
936
+ greater= qsort([x for x in seq[1 :] if x>= pivot])
937
+ return lesser+ [pivot]+ greater
938
+
939
+ if __name__ == ' __main__' :
940
+ seq= [5 ,6 ,78 ,9 ,0 ,- 1 ,2 ,3 ,- 65 ,12 ]
941
+ print (qsort(seq))
942
+ ```
781
943
944
+ ## 找零问题
945
+
946
+ ``` python
947
+ def coinChange (values , money , coinsUsed ):
948
+ # values T[1:n]数组
949
+ # valuesCounts 钱币对应的种类数
950
+ # money 找出来的总钱数
951
+ # coinsUsed 对应于目前钱币总数i所使用的硬币数目
952
+ for cents in range (1 , money+ 1 ):
953
+ minCoins = cents # 从第一个开始到money的所有情况初始
954
+ for value in values:
955
+ if value <= cents:
956
+ temp = coinsUsed[cents - value] + 1
957
+ if temp < minCoins:
958
+ minCoins = temp
959
+ coinsUsed[cents] = minCoins
960
+ print (' 面值为:{0} 的最小硬币数目为:{1} ' .format(cents, coinsUsed[cents]) )
961
+
962
+ if __name__ == ' __main__' :
963
+ values = [ 25 , 21 , 10 , 5 , 1 ]
964
+ money = 63
965
+ coinsUsed = {i:0 for i in range (money+ 1 )}
966
+ coinChange(values, money, coinsUsed)
967
+ ```
968
+
969
+ ## 广度遍历和深度遍历二叉树
970
+
971
+ 给定一个数组,构建二叉树,并且按层次打印这个二叉树
972
+
973
+ ``` python
974
+ # 二叉树节点
975
+ class Node (object ):
976
+ def __init__ (self , data , left = None , right = None ):
977
+ self .data = data
978
+ self .left = left
979
+ self .right = right
980
+
981
+ tree = Node(1 , Node(3 , Node(7 , Node(0 )), Node(6 )), Node(2 , Node(5 ), Node(4 )))
982
+
983
+ # 层次遍历
984
+ def lookup (root ):
985
+ stack = [root]
986
+ while stack:
987
+ current = stack.pop(0 )
988
+ print current.data
989
+ if current.left:
990
+ stack.append(current.left)
991
+ if current.right:
992
+ stack.append(current.right)
993
+ # 深度遍历
994
+ def deep (root ):
995
+ if not root:
996
+ return
997
+ print root.data
998
+ deep(root.left)
999
+ deep(root.right)
1000
+
1001
+ if __name__ == ' __main__' :
1002
+ lookup(tree)
1003
+ deep(tree)
782
1004
```
783
1005
784
1006
785
1007
1008
+
1009
+
0 commit comments