如何假装自己是 GDB 糕手
一、基础调试命令
命令
描述
示例
gdb [可执行文件]
直接加载可执行文件调试
gdb my_program
gdb -p <PID> / gdb attach <PID>
附加到正在运行的进程
gdb attach 1234
break <函数名>
在函数入口设断点
break main
break <文件名>:<行号>
在指定文件行设断点
break main.cpp:10
break if <条件>
条件断点
break 100 if cnt == 100
run [参数]
启动程序
run --test
continue (c)
继续执行到下一个断点
c
next (n)
单步执行(不进入函数)
n
step (s)
单步执行(进入函数)
s
print <变量名>
查看变量值,可以直接打印表达式
print x
bt / backtrace
打印当前堆栈
bt
delete <断点号>
删除断点
delete 1
...
OS 与 PL Mutex 之三两事
仍然是面试速记。
死锁的 408 八股
考研 408 必背八股,谁都会问,但笔者全都以举例的方式逃过去了,不过还是记一下。
死锁的四大条件与预防死锁的四大方法(一一对应)
资源互斥,最不可能取消的条件,不互斥的资源自然也不会有同步需求,各管各的就好
持有并等待,反义词是检测到死锁就回退并重新获取锁,抛开极端情况不谈(时机恰恰好到无论怎么回退,两个资源争夺方都会以相同的顺序抢夺资源然后失败),这种方式比较好实现
不可剥夺,反义词是按某种规则检测到死锁后就老杀新或者新杀老,这样能保证同一时间一定有一个任务能被推进下去,被杀死的任务自动回退即可
环路等待,反义词是保持资源申请顺序一致,比如数据库给数据加行锁,无论是给哪条数据加,都要从第一条数据开始加,然后给每条数据依次加,不如直接加个大表锁,性能肯定更好,因此实践中其实比较难保证资源申请顺序一致。当然也有 B-tree 的 crabbing 协议这样的精巧的数据结构上锁方式。这个条件是基于持有并等待与不可剥夺才能成立的条件,一般来说无论是不满足持有并等待还是不满足不可剥夺,环路等待都将不成立。
避免死锁
预防死锁是设计静态的系统规 ...
设计模式速记
笔者是从所谓 组合优于继承 的 Golang、Rust 以及 Modern C++ 学起的,因此在不知不觉中跳过了 OOP 的相当部分学习,导致笔者在 OOP 的基础几乎不如刚经过期末考的大二学生,比如 OOP 的三大特性笔者就说不上来。
设计模式作为 OOP 的良好实践,笔者在没有学习之前已经看过了不少大型项目代码,因此也许能触类旁通罢。虽然从菜鸟教程来看,设计模式有多达数十种之多,但大家都知道 CS 最会造生词以增加初学者的学习门槛,常用的设计模式不超过十种。
对于 Javaer 的普遍技术水平不能报以太多期望,笔者在此对常用设计模式归纳总结一番以防 SB 面试官偷袭。
六大原则
开闭原则(Open Closed Principle,OCP),不要想着用子类修改父类,要改就用子类继承一套然后重写方法
单⼀职责原则(Single Responsibility Principle, SRP),一个类里写所有逻辑直接梦回面向过程
⾥⽒替换原则(Liskov Substitution Principle,LSP),保守的鸭子类型思想
依赖倒置原则(Dependency Inversio ...
消息队列笔记
数据传输语义
传输语义
说明
例子
at most once
最多一次:不管是否能接收到,数据最多只传一次。这样数据可能会丢失,
Socket,ACK=0
at least once
最少一次:消息不会丢失,如果接收不到,那么就继续发,所以会发送多次,直到收到为止,有可能出现数据重复
ACK=-1
Exactly once
精准一次:消息只会一次,不会丢,也不会重复。
幂等 + 事务 + ACK=-1
Acks
0,参考 UDP 协议,Producer 只管发。
1,只需要 Leader Broker 确认接收即可。熟悉分布式 DB 的朋友们都知道,没有多数 Follower 的 Commit 是不保证线性一致性的,这只是一个工程上的性能与正确性的 tradeoff。
-1 或者 all,需要多数 Follower 确认。
幂等性
引入 ProducerID 和 SequenceNumber,Producer 需要做的只有两件事:
初始化时像向 Broker 申请一个 ProducerID
为每条消息绑定一个 SequenceNumber
...
操作系统串记
进程间通信方式
Method
100 Byte Messages
1 Kilo Byte Messages
Unix Signals
–broken–
–broken–
ZeroMQ (TCP)
24,901 msg/s
22,679 msg/s
Internet sockets (TCP)
70,221 msg/s
67,901 msg/s
Domain sockets
130,372 msg/s
127,582 msg/s
Pipes
162,441 msg/s
155,404 msg/s
Message Queues
232,253 msg/s
213,796 msg/s
FIFOs (named pipes)
265,823 msg/s
254,880 msg/s
Shared Memory
4,702,557 msg/s
1,659,291 msg/s
Memory-Mapped Files
5,338,860 msg/s
1,701,759 msg/s
goldsborough/ipc-bench
Unix Sig ...
分布式唯一 ID 生成算法笔记
雪花算法
格式(64bit)
1bit 不用:因为二进制中最高位是符号位,1 表示负数,0 表示正数,生成的 id 一般都是用整数,所以最高位固定为 0
41bit 时间戳:这里采用的就是当前系统的具体时间,单位为毫秒
10bit 工作机器 ID(workerId):每台机器分配一个 id,这样可以标示不同的机器,但是上限为 1024,标示一个集群某个业务最多部署的机器个数上限
12bit 序列号(自增域):表示在某一毫秒下,这个自增域最大可以分配的 bit 个数,在当前这种配置下,每一毫秒可以分配 2^12 = 4096 个数据
特点
全局唯一性:雪花算法可以保证集群系统的 ID 全局唯一
趋势递增:由于强依赖时间戳,所以整体趋势会随着时间递增
单调递增(×):不满足单调递增,在不考虑时间回拨的情况下,虽然在单机中可以保持单调递增,但在分布式集群中无法做到单调递增,只能保证总体趋势递增
信息安全指的是 ID 生成不规则,无法猜测下一个
时间回拨
简单说就是时间被调整回到了之前的时间,由于雪花算法重度依赖机器的当前时间,所以一旦发生时间回拨,将有可能导致生成的 ID ...
data-engineer
不同岗位、不同公司、不同面试官问的内容是不一样的。大数据开发包括 Hadoop(ETL,Mapreduce),Spark(SparkSql 和 SparkStreaming),Python 等,看你偏向的技术了。另外大数据开发看是否偏向数仓开发和数据分析,又会不一样。不同的面试官和公司用到的技术栈也不一样,问的问题也会有很大差别的。
我说说我面试大数据开发岗面试官常问的问题吧。因为我简历项目项目经验注重实时流处理这方面,在面试时,面试会在这些方面问的比较深,我前后梳理一遍吧。
一般上来就是自我介绍,谈下工作经历和项目经验,面试官会根据你的项目经验对你进行技术面试。
Java 是必问的,不过问的不深,把 Javase 部分吃透,足以应付 Java 部分的面试。
Hadoop 生态,Yarn、Zookeeper、HDFS 这些底层原理要懂,面试经常被问。
Mapreduce 的 shuffle 过程这个也是面试被常问的。
Hbase 和 HIve,搞大数据这些不懂真的说不过去。
Mysql、Oracle 和 Postgres 数据库操作要回,Sql 要会写。
linux 操作系统,这个简 ...
计算机网络串记
名词解释
ARQ(Automatic Repeat reQuest,自动重传请求)
ARQ 是一种用于数据通信中的错误控制方法,旨在保证数据传输的可靠性。ARQ 协议通过在发送端和接收端之间引入确认机制来检测并纠正传输过程中出现的数据丢失或损坏问题。
停等式 ARQ(Stop-and-Wait ARQ):最简单的形式,每发送一个数据包后就停止并等待确认。只有在收到 ACK 之后才会发送下一个数据包。这种方法效率较低,因为发送方在等待确认时处于空闲状态。
回退 N 步 ARQ(Go-Back-N ARQ):允许发送方连续发送多个数据包而不需要立即等待每个数据包的确认。如果某个数据包未被正确接收,发送方需要重传从那个数据包开始到当前的所有后续数据包。
选择性重传 ARQ(Selective Repeat ARQ):类似于回退 N 步 ARQ,但更高效。它只需要重传那些确实丢失或损坏的数据包,而不是从出错点开始的所有后续数据包。这减少了不必要的重传,提高了效率。
TCP
三次握手与四次挥手
滑动窗口确认机制
拥塞控制算法
慢启动(Slow Start):在连接开始时或网络出 ...
GC 算法笔记
标记清除法
标记清除法主要包含两个步骤:
标记
清除
示例如下:
开启 STW,停止程序的运行,图中是本次 GC 涉及到的 root 节点和相关对象。
从根节点出发,标记所有可达对象。
停止 STW,然后回收所有未被标记的对象
标记清除法的最大弊端就是在整个 GC 期间需要 STW,将整个程序暂停。因为如果不进行 STW 的话,会出现已经被标记的对象 A,引用了新的未被标记的对象 B,但由于对象 A 已经标记过了,不会再重新扫描 A 对 B 的可达性,从而将 B 对象当做垃圾回收掉。
三色标记法
三色标记法将对象用三种颜色表示,分别是白色、灰色和黑色。
最开始所有对象都是白色的,然后把其中全局变量和函数栈里的对象置为灰色。第二步把灰色的对象全部置为黑色,然后把原先灰色对象指向的变量都置为灰色,以此类推。等发现没有对象可以被置为灰色时,所有的白色变量就一定是需要被清理的垃圾了。
初始标记阶段,指的是标记 GCRoots 直接引用的节点,将它们标记为灰色,这个阶段需要「Stop the World」。
并发标记阶段,指的是从灰色节点开始,去扫描整个引用链,然后将它们标记 ...
C 十十 面经杂文
校招 C++ 大概学习到什么程度
写明白下面这几个代码 +能讲明白几个 C++11/14/17 的特性
MyString
MyVector
MyLRU
MySingleton
MyHashTable
MySharedPtr
MyUniquePtr
再补一个 MyThreadPool
MyRingbuffer
MyReadWriteMutex
校招 C++ 大概学习到什么程度
STL,C++11
move 相关
这里需要构造一个方便指明不同对象的 class A,下面的实现是不符合复制、移动构造函数的语义的,请不要模仿:
12345678910111213141516171819202122#include <iostream>using std::cout, std::endl;class A {public: int id = 0; A() { cout << "Construct A" << endl; } A(A &a) { this->id = a ...