通常工程里不推荐自己写内存分配器,因为你费力写一个出来99%可能性没有内置的好,且内存出bug难调试 不过看书之余,你也可以动手自己试试,当个玩具写写玩玩:
1. 实现教科书上的内存分配器:
做一个链表指向空闲内存,分配就是取出一块来,改写链表,返回,释放就是放回到链表里面,并做好归并。注意做好标记和保护,避免二次释放,还可以花点力气在如何查找最适合大小的内存快的搜索上,减少内存碎片,有空你了还可以把链表换成伙伴算法,写着玩嘛。
2. 实现固定内存分配器:
即实现一个 FreeList,每个 FreeList 用于分配固定大小的内存块,比如用于分配 32字节对象的固定内存分配器,之类的。每个固定内存分配器里面有两个链表,OpenList 用于存储未分配的空闲对象,CloseList用于存储已分配的内存对象,那么所谓的分配就是从 OpenList 中取出一个对象放到 CloseList 里并且返回给用户,释放又是从 CloseList 移回到 OpenList。分配时如果不够,那么就需要增长 OpenList:申请一个大一点的内存块,切割成比如 64 个相同大小的对象添加到 OpenList中。这个固定内存分配器回收的时候,统一把先前向系统申请的内存块全部还给系统。
3. 实现 FreeList 池:
在你实现了 FreeList的基础上,按照不同对象大小(8字节,16字节,32,64,128,256,512,1K。。。64K),构造十多个固定内存分配器,分配内存时根据内存大小查表,决定到底由哪个分配器负责,分配后要在头部的 header 处(ptr[-sizeof(char*)]处)写上 cookie,表示又哪个分配器分配的,这样释放时候你才能正确归还。如果大于64K,则直接用系统的 malloc作为分配,如此以浪费内存为代价你得到了一个分配时间近似O(1)的内存分配器,差不多实现了一个 memcached 的 slab 内存管理器了,但是先别得意。此 slab 非彼 slab(sunos/solaris/linux kernel 的 slab)。这说白了还是一个弱智的 freelist 无法归还内存给操作系统,某个 FreeList 如果高峰期占用了大量内存即使后面不用,也无法支援到其他内存不够的 FreeList,所以我们做的这个和 memcached 类似的分配器其实是比较残缺的,你还需要往下继续优化。
Read more…
好几年没碰过 Flash 了,最近需要给 ActionScript 导出一些 C 接口,又抽空捡起来。项目大了以后 Flash Builder 卡的要死,经常是一个构建你就可以休息了,按一下 “.“ 它就开始搜索补全提示,你的符号多了以后,有时候 Flash Builder 近乎假死了。实在难以忍受,咨询了一些正在做页游的朋友,是否还在用 Flash Builder 。得到答案是:早就投奔 Flash Develop 了。
试了一下 FlashDevelop 果然腰也不酸了,腿也不疼了,十分流畅,界面类似 Visual Studio,同时还是免费的,可以彻底和笨重的 Flash Builder 说再见了。再次感叹 AS3 写起来真爽之余,记录一下安装配置过程:
Read more…
通常来讲,就是利用 select 的空余时间,来进行时钟检查,不管是 select / poll / epoll/ kevent,以下统称 select,它有一个等待时间作为参数,即没有事件时,最多 wait 多少时间,我们把这个作为网络库的基准频率,比如 10MS,或者 20MS, 25MS, 50MS,都是常用的几个值。
就是说网络库调用 select 等待事件时如果没有事件,那么最长等待 10MS 就返回了,这时再处理完所有网络事件后,就可以来处理时钟数据了。事件处理函数就是这样:
def update_events(milisec = 10): result = selector.select(milisec) for fd, event in result: do something with socket event current = time.time() update_timer(current)
while 1: WAIT_MILLISEC = 10 update_events(WAIT_MILLISEC)
关键就是这个两次 select 中间 update_timer 的任务:集合中检查需要唤醒的时钟,并且调用它们的回调函数,来驱动整个服务器的时钟运行,以最简单的扫描法为例:
def update_timer (current): for timer in available_timers: while current >= timer.expires: timer.callback(current) timer.expires += timer.period
available_timers 记录着当前可用的所有 timer 的集合,expires 是他们需要被触发的时间,如果当前时间大于等于这个 expires,认为该 timer 需要被触发到。注意 timer.expires 更新的时候是 += 周期,而不是 = current + 周期,后者会导致误差积累,长时间运行后偏差越来越大。同时这里需要 while,因为可能跨越两个以上周期,当然只运行一次的 timer 就不需要了,这里只是简化下。
比如 libevent 里面的主循环 event_base_loop 每次 select 完毕后就调用一次 timeout_process。
这就是 Timer 调度的基本原理。
可能你会发现每次 select 结束都要扫描整个 available_timers 集合,是一个非常费时间的事情,那么首先想到的就是优先队列了:将 Timer 节点按照 expires 的先后顺序,将最快要发生的超时节点放在前面,每次检测队列头就可以判断是否超时了。
Read more…
可以使用经典的 TT 来测试你的打字速度,注意是包含数字和符号的文章(Menu->Test->All key)
软件很简单,按照箭头指着的位置,快速输入上面的单词即可,输入完会有评分的。
TT是比较好的打字练习程序,直到今天,公司内都用作给新人练习打字速度用。不当能测试,还有比较详细的课程,教你从纯单词打起,逐步到数字,标点符号等。
我做过一个 DOSBOX版本的 TT (tt.exe 是 DOS下的程序),双击 TT.BAT 即可在 Win7/8 启动 http://www.skywind.me/mw/images/e/eb/TT-Dosbox.7z
我当时用 TT 测试 All Key 的时候,已经写过好多年程序了,自己觉得自己打字不慢,英文可以流利盲打,数字和符号需要看一下,结果 TT 测试下来,打字速度只有 31 WPM ,属于垫底的角色,丢死人了。
Read more…
老板非技术或者非产品出生的,从来没参与过项目开发的,对技术工作想想太过简单化的,去了也白去。这样的老板,对 CTO 的定位就是 “魔术师”,好像招聘到一个厉害的魔术师过来,再宏伟的需求,只要 CTO 够牛,最多几天时间,他都能把想要的东西给 “变” 出来。这就是不懂研发的老板们对 CTO 的真实期望,你以其花一两年时间慢慢 “教” 会他研发的艰辛,还不如考虑一下换个地方。
再者前期东西做出来前你很重要,后期东西出来后靠运营的时候你就比较尴尬了。老板无法正确评估你的价值,东西出来后,技术做的好就是不出问题,老板看不到,看得到的时候就是出问题的时候了,好像每次赢得利润都是商务和运营的努力。
你需要争取资源和开发时间进行优化或者开发一些非功能性,界面上体现不出来的功能,你都会发现异常难以向老板说明他的重要性。
每次发奖金和分红的时候,老板都会心理暗自嘀咕,“我靠,技术那么高的工资,原来一直跟着我干的那帮商务兄弟们才拿那么点,利润又是他们创造的,好可怜呀。技术成天没开发啥新功能,老的也做不好,上周才出一次事故。。。。”
记住,这样的老板,对 CTO 的期望基本上就是停留在 “变魔术” 三个字上,出外创业,除了项目靠不靠谱,还得看看创始人的基因及期望。
等到哪天你离职时,期权股份一回收,你这两年就白忙了。
以上为身边大数据统计出来的结论,信则有,不信则无。
现在很多人一提高性能后端开发,就总会想起 EPoll 来。其实一个成熟的高性能服务器,epoll相关的代码,不到万分之一。
而往往入门服务端的人,都天真的人为:高性能服务端开发 == EPOLL,真好笑,之所以会出现 epoll这种被捧上天的垃圾,明明就是 posix 或者最早版本的 unix/bsd/systemv 的设计考虑不完善。
按今天的眼光反思 posix 和 unix/bsd/systemv 当年的设计,epoll 这种补丁就不应该实现。
异步 reactor 框架应该就只有一个简单而统一的 selector 就足够了,所有系统都相同,提供:
register: 注册
unregister:删除
set:设置
wait:等待事件
read:读取事件
wake:将等待中的 wait 无条件唤醒
别以为这些 poll / epoll / kevent / pollset / devpoll / select / rtsig
是些什么 “高性能服务器” 的 “关键技术”,它们只是一个 API,而且是对原有系统 API设计不完善打的补丁,各个内核实现了一套自己的补丁方式,它们的存在,见证了服务端技术碎片化的遗憾结果。
之所以会有这些乱七八糟的东西,就是早期的 posix / unix/ bsd /systemv 设计不周全,或者不作为留下的恶果。并非什么 “关键技术”。
不用提 windows 的 iocp了,proactor 会来强奸你代码结构,遭到大家唾弃是有原因的。不像 reactor那样优雅,所以 java nio 选择 reactor 是正确的。即便在 reactor 中,epoll 也是一个失败的例子,调用最频繁的 epoll_ctl 的系统占用估计大家都感受过吧,这方面 epoll 真该象 kevent / pollset 学习一下。
Recent Comments