- 博客(136)
- 收藏
- 关注
原创 一种更快的Kmeans原理与实现
如果我们预先计算出了这两个质心之间的距离D(j1,j2),则如果计算发现2D(x,j1)≤D(j1,j2),就可以知道D(x,j1)≤D(x,j2)。在距离计算方面,每次迭代的最小距离计算次数为k*(k-1)/2,对于较大的k(例如矢量量化),这可能是主要的开销。我们不维护每一对点的距离的上界,只维护一个数据点到它的锚定点的距离的上界u(x)。我们维护每一个数据点x到中点c的距离的下界l(x,c),一开始赋值为距离,迭代的时候,根据定理2,d)的时间复杂度,其中k是中心点的数量,d是数据的维度。
2024-01-20 15:39:31 831
原创 linux 内存
but 它又不能被杀掉,这就会导致随着它的内存开销变大,OOM killer不停地被唤醒,从而把其他进程一个个给杀掉,我们之前在生产环境中就遇到过类似的案例。系统内存不足时会唤醒OOM killer来选择一个进程给杀掉,在我们这个例子中它杀掉了这个正在内存泄漏的程序,该进程被杀掉后,整个系统也就变得安全了。如果此时系统中有很多进程都在申请内存,那么这些申请内存的进程都会被阻塞在这里,这就形成了一个恶性循环,甚至会引发系统长时间无响应(然后是cat /proc/meminfo。这两个是最开始排查的用的。
2024-01-12 19:48:40 545
原创 linux磁盘总结
linux读写磁盘,如果都是采用directIO的话,效率太低,所以我们在读写磁盘上加了一层缓存,page_cache。读的话,如果page_cache有的话,就不用向磁盘发出请求。写的话,也直接写入的page_cache就行了,异步刷回磁盘(操作系统不crash,不会丢失)。如果查看page_cache的大小:cat /proc/meminfo。
2024-01-11 12:03:58 1046
原创 LLVM入门
LLVM的IR中间层面的抽象很好的解耦了高级语言和机器环境,不想gcc N * M的复杂度。LLVM的IR可以解释执行,同时也可以编译执行。数据库编译查询可以通过两者混用来提高效率。前端生产AST树通过各种优化pass生成DAG,然后通过我们的后端生产汇编代码。同时我们熟知的clang只不过是llvm编译组件的前端。前端要注意有语义分析,这可能就是C++说的语义吧。
2024-01-04 11:52:22 342
原创 网络协议疑点记录
这种算法的基本思路是:当一个路由器启动的时候,首先是发现邻居,向邻居 say hello,邻居都回复。在 BGP 里面,除了下一跳 hop 之外,还包括了自治系统 AS 的路径,从而可以避免坏消息传得慢的问题,也即上面所描述的,B 知道 C 原来能够到达 A,是因为通过自己,一旦自己都到达不了 A 了,就不用假设 C 还能到达 A 了。eBGP 和 iBGP。距离矢量路由算法,bellman-ford算法,每个路由节点知道全局的路由信息,通过和邻居交换信息得到,然后一个问题就是好消息传的快,坏消息传的慢,
2023-12-10 19:59:40 1196
原创 epoll协程简述
当有需要等待的时候,就切换出去,要用汇编保存这个栈rsp。让出的时候,要根据协程上下文保存这个栈。运行时,要根据协程上下文恢复出这个栈。
2023-11-17 20:48:13 191
原创 网络解析(二)
这个过程就和发往同一个网段的其他机器是一样的:将源地址和目标 IP 地址放入 IP 头中,通过 ARP 获得网关的 MAC 地址,将源 MAC 和网关的 MAC 放入 MAC 头中,发送出去。每只手的 IP 地址都和局域网的 IP 地址相同的网段,每只手都是它握住的那个局域网的网关。如果是同一个网段,例如,你访问你旁边的兄弟的电脑,那就没网关什么事情,直接将源地址和目标地址放入 IP 头中,然后通过 ARP 获得 MAC 地址,将源 MAC 和目的 MAC 放入 MAC 头中,发出去就可以了。
2023-10-18 00:18:24 532
原创 网络解析(一)
那什么叫三层设备呢?很多人看到这里就会想,既然这样,整个互联网的通信,全部用 MAC 地址好了,只要知道了对方的 MAC 地址,就可以把信息传过去。对于 192.168.1.6 这台机器来讲,虽然路过它家门的这个包,目标 IP 是它,但是无奈 MAC 地址不是它的,所以它的网卡是不会把包收进去的。在 IP 地址的上一行是 link/ether fa:16:3e:c7:79:75 brd ff:ff:ff:ff:ff:ff,这个被称为 MAC 地址,是一个网卡的物理地址,用十六进制,6 个 byte 表示。
2023-10-16 12:20:20 133
原创 linux内核分析:docker与隔离
在内核里面,对于任何一个进程 task_struct 来讲,里面都会有一个成员 struct nsproxy,用于保存 namespace 相关信息,里面有 struct uts_namespace、struct ipc_namespace、struct mnt_namespace、struct pid_namespace、struct net *net_ns 和 struct cgroup_namespace *cgroup_ns。如果你不相信任何一个云,怕被一个云绑定,怕一个云挂了自己的应用也就挂了。
2023-10-06 12:14:03 290
原创 linux内核分析:虚拟化
我知道我不是物理机内核,我知道我是虚拟机,我没那么高的权限,我很可能和很多虚拟机共享物理资源,所以我要学会排队,我写硬盘其实写的是一个物理机上的文件,那我的写文件的缓存方式是不是可以变一下。和用户态 qemu 对应的内核 KVM,对于虚拟机有一个结构 struct kvm 表示这个虚拟机,这个结构会指向一个数组的 struct kvm_memory_slot 表示这个虚拟机的多个内存条,kvm_memory_slot 中有起始页号,页面数目,表示这个虚拟机的物理内存空间。
2023-10-05 15:49:14 159
原创 linux内核分析:网络协议栈
接下来的调用链为:ip_route_output_ports->ip_route_output_flow->__ip_route_output_key->ip_route_output_key_hash->ip_route_output_key_hash_rcu。在 ip_rcv 中,得到 IP 头,然后又遇到了我们见过多次的 NF_HOOK,这次因为是接收网络包,第一个 hook 点是 NF_INET_PRE_ROUTING,也就是 iptables 的 PREROUTING 链。
2023-10-04 15:09:25 288
原创 智能指针那些事
《Effective Modern C++》学习笔记之条款二十一:优先选用std::make_unique和std::make_shared,而非直接new - 知乎
2023-10-02 20:01:20 163
原创 守护进程解析
3、若父进程退出导致进程组成为孤儿进程组,且该进程组中有进程处于停止状态(收到SIGSTOP或SIGTSTP信号),该信号会被发送到该进程组中的每一个进程。1、终端关闭时,该信号被发送到session首进程以及作为job提交的进程(即用 & 符号提交的进程);2、session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程;,如果调用此函数的进程不是一个进程组的组长,则此函数创建一个新会话。会话:会话(session)是一个或多个进程组的集合,进程调用 setsid。
2023-10-02 17:22:04 143
原创 linux RCU文章汇总
浅析linux kernel RCU机制 - thinkycx.meLinux RCU机制深入理解 Linux 的 RCU 机制-腾讯云开发者社区-腾讯云
2023-09-28 16:46:48 60
原创 linux内核分析:进程通讯方式
我们知道,信号的到来时间是不可预期的,有可能程序正在调用某个漫长的系统调用的时候(你可以在一台 Linux 机器上运行 man 7 signal 命令,在这里找 Interruption of system calls and library functions by signal handlers 的部分,里面说得非常详细),这个时候一个信号来了,会中断这个系统调用,去执行信号处理函数,那执行完了以后呢?在 fifo_open 里面,创建 pipe_inode_info,这一点和匿名管道也是一样的。
2023-09-20 20:11:44 107
原创 Linux内核分析:输入输出,字符与块设备 31-35
所以,在 bdget 中,BDEV_I 就是通过 bdev 文件系统的 inode,获得整个 struct bdev_inode 结构的地址,然后取成员 bdev,得到 block_device。bd_part 指向的某个分区的 hd_struct,bd_contains 指向的是整个块设备的 block_device。上面的例子中,logibm_interrupt 这个中断处理函数,先是获取了 x 和 y 的移动坐标,以及左中右的按键,上报上去,然后返回 IRQ_HANDLED,这表示处理完毕。
2023-09-19 20:58:18 135
原创 linux内核分析:内存映射,文件系统
对于用户态的内存分配,或者直接调用 mmap 系统调用分配,或者调用 malloc。正常情况下,用户态的内存都是可以换出的,因而一旦发现内存中不存在,就会调用 do_page_fault。内核态中 vmalloc 分配的部分会被换出,因而当访问的时候,发现不在,就会调用 do_page_fault。对于内核态,kmalloc 在分配大内存的时候,以及 vmalloc 分配不连续物理页的时候,直接使用伙伴系统,分配后转换为虚拟地址,访问的时候需要通过内核页表进行映射。至此,内核态的内存映射也讲完了。
2023-09-18 10:16:52 119
原创 linux内核分析:线程和进程创建,内存管理
假设物理内存里面,896M 到 1.5G 之间已经被用户态进程占用了,并且映射关系放在了进程的页表中,内核 vmalloc 的时候,只能从分配物理内存 1.5G 开始,就需要使用这一段的虚拟地址进行映射,映射关系放在专门给内核自己用的页表里面。如果打开这个函数,看到的是对红黑树的查找,找到的是原堆顶所在的 vm_area_struct 的下一个 vm_area_struct,看当前的堆顶和下一个 vm_area_struct 之间还能不能分配一个完整的页。如果分成 4KB 一个页,那就是 1M 个页。
2023-09-17 12:52:26 389
原创 linux内核分析:进程与调度
这个时候,用户 A 再启动这个游戏的时候,创建的进程 uid 当然还是用户 A,但是 euid 和 fsuid 就不是用户 A 了,因为看到了 set-user-id 标识,就改为文件的所有者的 ID,也就是说,euid 和 fsuid 都改成用户 B 了,这样就能够将通关结果保存下来。在上面的例子中,A 切换到 B 的时候,运行到 __switch_to_asm 这一行的时候,是在 A 的内核栈上运行的,prev 是 A,next 是 B。如,用户 A 想玩一个游戏,这个游戏的程序是用户 B 安装的。
2023-09-16 13:26:58 188
原创 linux内核分析:x86,BIOS到bootloader,内核初始化,syscall, 进程与线程
在代码里面的定义为 struct elf32_phdr 和 struct elf64_phdr,这里面除了有对于段的描述之外,最重要的是 p_vaddr,这个是这个段加载到内存的虚拟地址。在这之前,我们所有遇到过的程序都非常非常小,完全可以在实模式下运行,但是随着我们加载的东西越来越大,实模式这 1M 的地址空间实在放不下了,所以在真正的解压缩之前,lzma_decompress.img 做了一个重要的决定,就是调用 real_to_prot,切换到保护模式,这样就能在更大的寻址空间里面,加载更多的东西。
2023-09-15 16:29:45 197
原创 linux 堆探索
堆的虚拟地址是连续的,是brk来分配,brk是一个指针指向堆顶的指针,并且是可以复用的,但是只有在堆顶空闲128k时,才收缩,也就是说,为了减少page_fault,可重用,开销小的特点。但是会内存碎片,但是分配内存>128k时,就是mmap,可以unmmap立即释放虚拟内存。也不都是mmap来分配吧(
2023-09-10 16:52:08 94
原创 linux编程第一部分总结
enable_shared_from_this<>是用来做回调的,因为多线程中可能对象的生命周期比传出去的this指针短,同时为了不延长对象的生命周期,我们把shared_ptr转成weakptr.对象析构很复杂,我们采用shared_ptr和weak_ptr来做。
2023-09-03 12:39:36 185
原创 Redis多机实现
主从结构一大难题------------如何保障一致性,对这个一致性要求不是很高,因为redis是用来做缓存的。同时我们要自动化进行故障转移-------哨兵机制,同时哨兵也可能crash,所以我们要引入哨兵集群的概念。为啥要有多机--------------1.容错 2.从服务器分担读压力。同时redis还提供了分布式数据库解决方案--------redis集群。所以我们要一个缓冲区来记录下断线的命令以及复制的offset。实际上就是一个raft算法。选举主节点是raft算法。
2023-08-23 16:04:38 887
原创 innodb索引与算法
B+树在innodb的插入有三种模式page_last_insert, page_dirction, page_N_direction。而在bustub里面的B+树就是page_N_direction,如果是自增主键的话,就是上面这样的插入法。
2023-08-17 22:20:03 156
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人