├── CPU阿甘:函数调用的秘密.md ├── JSP: 一个装配工的没落.md ├── TCP - IP之大明内阁.md ├── TCP-IP之蓟辽督师.md ├── Java : 一个帝国的诞生.md ├── TCP-IP 之 大明王朝邮差 ├── CPU阿甘.md ├── 我是一个线程.md ├── CPU阿甘之烦恼.md ├── Javascript:一个屌丝的逆袭.md ├── 我是一个Java class.md └── README.md /CPU阿甘:函数调用的秘密.md: -------------------------------------------------------------------------------- 1 | ## CPU阿甘:函数调用的秘密 2 | 3 | 原创: 老刘 码农翻身 4 | 5 | 6 | 我是CPU阿甘, 上次我给大家承诺过,要讲一讲函数调用的秘密, 这个确实有点复杂, 想透彻的理解机器代码层面的函数调用不容易。 7 | 8 | 我也是从无数的指令中悟出这个函数调用的秘密的, 所以慢慢来,不要急。 放松心情, 慢慢的品味, 你可能需要多看几遍才能明白。 9 | 10 | 但是你一旦理解了,绝对物超所值,因为你会了解到汇编,寄存器,指针,以及他们在一起到底是怎么工作的。 11 | 12 | 首先, 一个程序一条一条的指令都的老老实实的放在内存的一个地方,这个地方是Linux老大分配的, 我干涉不了, 但是这些指令都是我打电话给硬盘, 让他给运输到内存的。 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /JSP: 一个装配工的没落.md: -------------------------------------------------------------------------------- 1 | ## JSP: 一个装配工的没落 2 | 3 | 原创: 刘欣 码农翻身 4 | 5 | 没错, 我就是大名鼎鼎的JSP, 服务器端“装配工”之王。 你要是没听说过我就实在太out了, 你要问我到底是干什么的, 其实很简单, 就是把页面模板和数据给装配起来, 变成HTML发送给浏览器, 然后你才能看到啊。 6 | 7 | 奥, 不, 我一提到装配工之王, 那个叫PHP的已经拿着板砖怒气冲冲的过来了, 好吧, PHP大哥, 你才是老大,最好的编程语言, Web编程之王, 我的意思是Java 装配之王,好吧, 消消气。 8 | 9 | 1 10 | 11 | ## 黑暗岁月 12 | 13 | 遥想当年, Web编程刚刚诞生的时候, 大家只能用Perl , C语言等以CGI的方式来输出 HTML, 那可真是一段黑暗的、可怕的岁月。 14 | 15 | 我真是难以想象CGI的小伙子是怎么装配网页的, 其实也无所谓装配, 他们就是字符串拼接而已,可怜的孩子们甚至都不知道字符串到底是什么含义。 16 | 17 | 有图有真相, 看看吧: 18 | 19 | ![2](http://mmbiz.qpic.cn/mmbiz_png/KyXfCrME6UL1r0gYVVC1QMJsnhMjIXFRl5ugg3eiaydHnmI2Rp9icXLLnB6f3oJBvmbGP03OFAU94mBsEgicuDJUA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 20 | 21 | 这还不涉及到人家用户通过浏览器传递过来的参数, 那处理起来就更不容易了。 22 | 23 | 我有时候挺佩服这时候的码农的, 用这么低级原始的方式竟然还能写出复杂的Web网站, 实在是了不起啊。 24 | 25 | 2 26 | 27 | ## 服务器端动态页面 28 | 29 | 1996年, “恶名远扬”的微软推出了ASP(Active Server Page), 这个新的页面装配工和CGI小伙子们可是大不相同, 因为他能够支持在HTML页面中嵌入代码! 这下子动态的Web页面可就轻松多了。 30 | 31 | 完全可以先用一些可视化编辑器像FrontPage, Dreamweaver 先把界面创建好, 然后码农再其中塞入代码。 32 | 33 | ![3](http://mmbiz.qpic.cn/mmbiz_png/KyXfCrME6UL1r0gYVVC1QMJsnhMjIXFR7OrTTzb3icWdpoibiaZVBcmrRzpJWt7O67vthhg8YOL84Mc49QunJkDew/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 34 | 35 | 看看这张图, 你应该能明白ASP装配工是怎么干活的, 页面看起来就像是一个html静态文本, 被<% %>包裹的就是代码了, 装配工需要运行他们, 然后把产生的数据嵌入到html当中。 36 | 37 | 38 | 39 | 由于微软的强势, ASP这厮可真是火了一把, 尤其是在中国。 40 | 41 | 42 | 43 | 我们Sun公司看到这种情况, 自然会奋起直追, 很快我这个装配工JSP (Java Server Pages)就诞生了。 44 | 45 | 46 | 47 | ASP主要用VBScript 这样的脚本语言 ( 唉, 我估计微软的Bill Gates实在是太喜欢VB了, 连一个脚本语言也要搞的VB很像), 我就完全不同了, 我用的可是被无数人喜爱的Java, 跨平台啊。 48 | 49 | 50 | 51 | 每当我用这一点嘲笑ASP的时候, 他都会说: “别整天在这里乱喷了, 说来说去, 你本质上不也是一个模板吗? 你看看你装配的那些页面, 代码和HTML混杂在一起, 搅的乱七八糟, 没有任何美感。 对了,听说你有个JSP中太长了,竟然爆出了无法编译的错误, 实在是太可笑了, 哈哈哈。” 52 | 53 | 54 | 55 | ASP说的没错, 有个不着调的码农把绝大部分的业务逻辑都搞到了JSP 当中, 我实在是无法装配, 只好报错。 56 | 57 | 58 | 59 | 不过ASP也好不到哪里去, 也是HTML中混杂这大量代码。 60 | 61 | 3 62 | 63 | ## 标签库 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /TCP - IP之大明内阁.md: -------------------------------------------------------------------------------- 1 | ## TCP/IP之大明内阁 2 | 3 | 原创: 刘欣 码农翻身 4 | 5 | 本文是《TCP/IP之大明王朝邮差》的前传, 讲一讲大明内阁的各位大人是怎么设计TCP/IP网络的。 6 | 7 | 大明天启年间, 明熹宗朱由校醉心于木工, 重用宦官魏忠贤, 不上朝已经很久了。 8 | 9 | 内阁内阁首辅叶大人忧心忡忡, 大明各地民不聊生,大片田地荒芜, 强盗,野兽横行, 之前修建的官道也基本废弃了, 不但收不到各地送来的奏报, 自己昨天好不容易摆脱魏忠贤,面见了一次皇上, 但是请求颁发的一道圣旨竟然无法送到各个府县, 送信的邮差都被半路抢劫了,或者失踪了! 10 | 11 | 叶首辅决定召开一次内阁会议,研究下怎么建立一个可靠的,稳定的、通畅的上情下达机制。 12 | 13 | ## 虚电路 14 | 15 | 前来开会的大人们听了叶首辅说的情况, 立刻都是愁眉苦脸的, 面对这么一个艰巨的挑战, 没人愿意开口, 都是在不住的叹气摇头。 16 | 17 | 过了一炷香功夫, 韩大人看到首辅不断的给自己使眼色,只好开口了: “各位大人, 我有个不成熟的想法, 说出来大家评判一下。 现在主要的问题是强盗横行、野兽出没, 我想我们可以派出我们的大军, 沿路站岗, 五步一岗, 三部一哨, 给官道建立一个可靠的保障。 ” 18 | 19 | 朱大人道:“韩大人此法差矣! 我大明这么多官道, 大军再多也不够用啊。” 20 | 21 | 韩大人笑道: “朱大人, 看来你没明白, 我的意思不是把所有的官道都布上岗哨, 而是说我们要建立一个连接通道!” 22 | 23 | “连接? 什么连接? ” 朱大人说 “没听说过” 24 | 25 | “假如我们京城要和开封府通信, 中间会经过很多的市镇, 我们只需要派出一队官兵,把从京城到开封府的道路给保护好就可以了, 这样就不怕那些强盗虎豹, 等到双方通信一完,大军即可撤回, 去保护另外一个通信通道, 这就是用官兵建立一个连接!” 26 | 27 | 叶首辅道: ”韩大人说的有道理,至少能解决问题, 不过我们的主力大军都被派到东北对付努尔哈赤去了, 所以我们需要和沿途的市镇、驿站协商,主要让他们出兵, 和京城的大军一起建立安全的通道。“ 28 | 29 | “这样的话在一次通信中都可以走这个安全的通道, 很宽敞,很可靠, 但是代价也很高, 为了通信一次,得动用这么多士兵,还得和中间节点协商。 ” 朱大人也学会了抽象, 造出了”中间节点“这样的新词儿。 30 | 31 | 韩大人道:“嗯, 还有一点就是如果通道暂时不发信件的话, 就闲置浪费了。” 32 | 33 | 叶首辅道: “那也是没有办法的事情, 我们先这么试行一段时间吧。 ” 34 | 35 | ![1](http://mmbiz.qpic.cn/mmbiz_png/KyXfCrME6ULYSsVhtQMdjuElo5SUDxZmMWQsgHOHLVD4jJWGOvyLjFfwScGicyQbcRGZzXgpgtJFbib3LxTrq7LA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 36 | 37 | (码农翻身公众号注: 这就是所谓的虚电路, 绿色部分为连接通道, 所有的消息都从同一个通道上发送) 38 | 39 | ## 分组交换 40 | 41 | “虚电路”运行了半年, 终于勉强上情下达了, 但是被魏忠贤得知,添油加醋的给皇帝朱由校说了很多坏话, 木匠皇帝雷霆大怒,大骂内阁浪费国家人力物力, 下令立即停止。 42 | 43 | 内阁恨透了魏忠贤, 但是又不得不停止。 44 | 45 | 这一天皇上又没上早朝, 大家愁眉苦脸的聚到一起商议。 46 | 47 | 礼部右侍郎孙承宗突然想起了一件事情:“我巡防边关的时候听说袁崇焕使用了一个奇怪的办法来传递军务物资, 他不用军队在官道站岗,不用建立安全的连接通道,完全依靠马匹、骡子这样的牲畜进行通信。” 48 | 49 | “怎么可能? 马匹不通人性,跑丢了怎么办?” 50 | 51 | 孙承宗道:“他这些马是训练过的,身上带着信件或者物资, 可以在官道上走,每到一个驿站或者市镇,里边的衙役看看信件的目的地,喂喂马,然后把马引到下一个官道就可以了, 很省事。 当然具体到那个官道是衙役决定的, 他会搜集各种消息,确定那个官道匪患少、虎狼少。 ” 52 | 53 | (码农翻身注:驿站类似路由器,需要构建路由表, 转发数据分组) 54 | 55 | “这还解决不了问题, 路上没官兵保护, 马可能会把抢走,或者被虎豹吃掉, 这样物资还是丢了。” 56 | 57 | 孙承宗道: “这一点袁崇焕他们也想到了, 他们发明了一种叫失败重传的方法, 如果收不到对方的确认回信, 就会重新发送。 ” 58 | 59 | “重新发送的代价太高了吧, 毕竟是物资啊!” 60 | 61 | 62 | 63 | “是这样, 他们一般把一个大件的物资拆成小块, 因为一匹马也拉不了多少, 然后给每个小块变编号,哪个小块丢了, 就只发送那个编号的, 袁崇焕说他们有个叫‘幻月宝镜’的东西, 丢了的东西可以从中再取出来!” 64 | 65 | “这真是个宝贝啊, 一般人怎么可能有啊。” 66 | 67 | (插播寻人启事:感谢网友提供了幻月宝镜这个主意, 我忘记是谁了, 看到请和我联系。) 68 | 69 | 叶首辅道:“不过这倒是一个有意思的思路, 不需要事先建立真正的连接通道, 每个编号小块走的路可能也不一样, 完全由中间节点的衙役们来决定马匹的下一个路径是哪一个。 ” 70 | 71 | (码农翻身注: 这叫做分组交换) 72 | 73 | 孙承宗补充道:”叶大人看的很透彻, 不仅路径不同, 这些小块也可能不按次序(失序)到达。 他用这种方法其实是说中间节点并不承诺提供可靠的连接通道, 物资完全可能失序、重复、甚至丢失。 所谓可靠的传输完全由两个端点(例如京城和开封府)来实现“ 74 | 75 | ![2](http://mmbiz.qpic.cn/mmbiz_png/KyXfCrME6ULYSsVhtQMdjuElo5SUDxZmnnBgp8hiaicLXN0ULLlNwoiceWWUkUMibxp6kfXzJU41vlNK5PKkCaQ53w/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 76 | 77 | (码农翻身注: 京城午门给内乡县衙发了A1,A2, 京城德胜门给开封府发送B1,B2,B3, 图中显示分组的路径) 78 | 79 | 韩大人道: “首辅大人, 要不我们也试试?, 不过我们得想办法把幻月宝镜弄来。 ” 80 | 81 | 叶首辅道: “我们奏请皇上让袁崇焕进京述职, 让他把宝镜带来,这一次一定得让皇上支持,要不然还会中途夭折, 我马上进宫, 大家静候佳音吧。” 82 | 83 | (完) 84 | 85 | PS: 我会争取再写一篇前传,讲讲袁督师是怎么实现失败重传的。 86 | 87 | 公众号:码农翻身 88 | 89 | “码农翻身”公众号由工作15年的前IBM架构师创建,分享编程和职场的经验教训。 90 | 91 | 92 | -------------------------------------------------------------------------------- /TCP-IP之蓟辽督师.md: -------------------------------------------------------------------------------- 1 | ## TCP/IP之蓟辽督师 2 | 3 | 原创: 刘欣 码农翻身 4 | 5 | 本文续《TCP/IP之大明内阁》, 不了解背景的同学可以先看看上一篇文章, 当然这篇也是《TCP/IP之大明邮差》的前传, 主要讲一讲可靠性传输的原理。 6 | 7 | 袁崇焕奉圣旨进京,也被迫带来了他的心肝宝贝幻月宝镜。 8 | 9 | 他一进京,顾上休息, 立刻就先去拜见曾经举荐提报自己的恩师孙承宗, 看到自己的爱将风尘仆仆的赶来,虽然心疼, 稍事寒暄过后,还是立刻问起了怎么用幻月宝镜实现可靠传输的问题。 10 | 11 | 袁崇焕道: “老师有所不知, 这幻月宝镜虽好,但是如果没有失败重传的方法,一切都是白搭。 关外的环境比关内更加恶劣, 除了强盗野兽,还有飘忽不定的清军骑兵,随时打劫你。 ” 12 | 13 | “确实是实情, 老夫当年巡视辽东的时候也看到了, 那你发出去物资以后, 是不是要等待对方的回复确认啊?” 14 | 15 | “老师说的对,这也是我们刚开始的设想, 请看这张状态图:” 16 | 17 | ![1](http://mmbiz.qpic.cn/mmbiz_png/KyXfCrME6UJ9QbNuclyXXtLmQnOzRoZoOwhKtFZUovTpMkjcK4dkPoFxFWibnHWDs05Er5ko27TBRkgZ96e0T7g/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 18 | 19 | “状态图是什么东西? 你自己弄的?” 20 | 21 | 22 | “不, 这是荷兰红毛送红衣大炮的时候教我画的, 他们那边的人很擅长搞这种玩意, 说是‘科学’, 这张图的第一个状态是‘等待发送数据’, 然后发送分组数据进入了第二个状态‘等待反馈’, 此时如果对方发来了反馈说‘收到了’, 那就回到第一个状态, 否则, 重发之前的数据” 23 | 24 | “荷兰红毛还是挺厉害的, 这是个描述系统的好方法啊,比纯用我们汉字好多了。 ” 25 | 26 | “是的老师, 这个状态图的问题就是:如果对方发回的反馈损坏了改怎么办?” 27 | 28 | 孙承宗道:“有道理, 如果反馈损坏了, 发送方将无法理解接收方是否收到数据分组, 只好重新发送上一个分组, 但是从接收方来看, 没法区分这个分组是新的还是一次重传, 这就麻烦了。 ” 29 | 30 | “所以我和满桂、祖大寿他们商量了下, 我们采用给数据编号的办法来解决这个问题, 第一次发送编号为A的, 然后就等待针对A的反馈, 如果反馈没法识别或者是没收到, 那就重新发送, 如果反馈是‘收到了’, 那就发送分组编号为B的数据。 ” 31 | 32 | ![2](http://mmbiz.qpic.cn/mmbiz_png/KyXfCrME6UJ9QbNuclyXXtLmQnOzRoZoyeYtkDHq8icrg871dicMibnwZAST34KkKy1FbwQoYQ3Fr8etLMT8N52hA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 33 | 34 | “老师明鉴, 我们确实遇到了这个问题, 于是就搞了一个沙漏定时器, 针对上面的状态做了改进, 分组一发送就开始计时,如果超时就重新发送同一分组, 像这样:” 35 | 36 | ![3](http://mmbiz.qpic.cn/mmbiz_png/KyXfCrME6UJ9QbNuclyXXtLmQnOzRoZoHVufLPXSfubnCd7WD09531ULELK8y26Xcic6p3w98YMQBVRlkevzGhQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 37 | 38 | 孙承宗道:”好复杂啊,老夫这脑子里全是四书五经, 这状态图让人头蒙啊。 “ 39 | 40 | 41 | 师生二人正聊着, 下人通报首辅叶大人来了。 42 | 43 | 同样是老学究的叶首辅看到了袁崇焕画的西洋状态图, 大为吃惊,心想袁崇焕赢得宁远大捷和宁锦大捷,果然是与众不同。 44 | 45 | 经过袁崇焕连番讲解,叶首辅终于明白了这是怎么回事, 他捻着胡子思忖一下, 马上提出一个问题:“你每次发送一个分组都得等待, 多慢啊, 能不能连续发送?” 46 | 47 | 孙承宗和袁崇焕对视一眼, 心想果然姜还是老的辣。 48 | 49 | 袁崇焕道:“叶大人高瞻远瞩, 思虑缜密,属下佩服。 这个问题我们把我们困住了很久才想出一个办法, 这个方法约定,发送方可以连续的发送分组,但是有限制数量,例如只能连续发送4个, 我们称之为窗口, 发送窗口满了就不能发了,需要等待接收方的确认, 当确认来了以后才能继续发送, 向前移动窗口 。” 50 | 51 | ![3](http://mmbiz.qpic.cn/mmbiz_png/KyXfCrME6UJ9QbNuclyXXtLmQnOzRoZoFfvyYq43Os5boXGIpZIsmWdF8lKLVYxbqp7wyjicKFcNl7UnVsgel8g/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 52 | 53 | “这又是个什么图? ” 叶首辅问到。 54 | 55 | “这也是红毛们教我的,可以称为交互图, 大人请看, 我们发送到分组4的时候, 窗口满了, 就停止发送, 只有等到分组1的确认(acknowledge, 简称ACK)来了以后,才继续发送下一个分组。” 56 | 57 | 孙承宗道: “我看到分组3在发送当中丢失了, 超时后重新发送, 可是接收端明明收到了分组4, 5, 6还要丢弃啊。 ” 58 | 59 | 袁崇焕道:“这个办法是满桂最先提出的, 他是一个粗人, 想出的方法也很粗暴, 非常依赖幻月宝镜, 把失败分组及其以后的全部重新发送, 的确浪费。” 60 | 61 | (码农翻身注: 这叫做回退N步协议) 62 | 63 | 叶首辅道:“很明显, 你们得选择性的重传那些丢失的分组。” 64 | 65 | “大人说的对, 请看这个图:” 66 | 67 | ![4](http://mmbiz.qpic.cn/mmbiz_png/KyXfCrME6UJ9QbNuclyXXtLmQnOzRoZoziakNKBWJWXsI36JvKXmEZt0YXOOPChdz1qVppuu5uKiawZSXMPPzp7Q/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 68 | 69 | “这个图中只发送丢失的分组3, 在接收端会暂时缓存分组4,5,6, 这样就省了很多事了” 70 | 71 | (码农翻身注:这叫做选择性重传) 72 | 73 | 叶首辅一拍大腿道: “好 !应该不错了, 我们就用这种办法来建立大明的可靠传输网络吧“ 74 | 75 | 接着他又郑重的补充到 : “ 二位要注意, 这些失败重传的方法,是我们三人的秘密, 绝不能让魏阉党知道, 要不然他又要去找皇上邀功请赏了。” 76 | 77 | (码农翻身注:这只是可靠性传输的原则, 实际的TCP协议要更复杂,需要考虑双向的全双工通信,想了解详情的可以看《TCP/IP详解 卷1》) 78 | 79 | 公众号:码农翻身 80 | 81 | “码农翻身”公众号由工作15年的前IBM架构师创建,分享编程和职场的经验教训。 82 | -------------------------------------------------------------------------------- /Java : 一个帝国的诞生.md: -------------------------------------------------------------------------------- 1 | ## Java : 一个帝国的诞生 2 | 3 | 原创: 刘欣 码农翻身 4 | 5 | ![1](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6ULJ7LTlWYwnmtRUdR2iaCmKokR2ta8B4JHGuYo9FzPrNyib73KvevVyksP8y7jBs2mAZ0WnWk5HqLKg/640?wx_fmt=jpeg&tp=webp&wxfrom=5) 6 | 7 | 1 8 | ## C语言帝国的统治 9 | 10 | 现在是公元1995年, C语言帝国已经统治了我们20多年, 实在是太久了。 11 | 12 | 1972年, 随着C语言的诞生和Unix的问世, 帝国迅速建立统治, 从北美到欧洲, 从欧洲到亚洲, 无数程序员臣服在他的脚下。 13 | 14 | 帝国给我们提供了极好的福利:贴近硬件, 运行极快, 效率极高。 15 | 16 | 使用这些福利, 程序员们用C 开发了很多系统级软件,操作系统, 编译器, 数据库,网络系统..... 17 | 18 | 但是帝国也给我们安上了两个沉重的枷锁: 指针和内存管理 19 | 20 | 虽然指针无比强大, 能直接操作内存, 但是帝国却没有给我们工具去做越界的检查, 导致很多新手程序员轻易犯错。 21 | 22 | 至于内存管理, 帝国更完全是放任的态度: 你自己分配的空间, 自己去释放 ! 23 | 24 | 更要命的是这些问题在编译期发现不了, 在运行时才会突然暴露, 常常让我们手忙脚乱, 昏天黑地去调试。 25 | 26 | 我们的大量时间和宝贵的精力都被浪费在小心翼翼的处理指针和内存分配上。 27 | 28 | 每个程序员都被这两个东西搞的焦头烂额! 29 | 30 | 帝国宣称的可移植性骗了我们,他宣称我们在一个机器上写的程序, 只要在另外一个机器上编译就可以了, 实际上不是这样。 他要求我们尽量用标准的C函数库。其次,如果遇到了一些针对特定平台的调用, 需要对每个平台都得写一份 ! 有一点点小错误,都会导致编译失败。 31 | 32 | 1982年,帝国又推出了一门新的语言C++, 添加了面向对象的功能,兼容C, 有静态类型检查, 性能也很好。 33 | 34 | 但是这门新的语言实在是太复杂了, 复杂到比我聪明的多的人都没有办法完全掌握这门语言,它的很多特性复杂的让人吃惊。 35 | 36 | C++在图形领域和游戏上取得了一些成功, 但是我一直学不好它。 37 | 38 | 39 | 2 40 | ## 反抗 41 | 42 | 我决定反抗这个庞大的帝国, 我偷偷的带领着一帮志同道合的兄弟离开了,我们要新建一块清新自由的领地。 43 | 44 | 为了吸引更多的程序员加入我们, 我们要建立一个新的语言,这个语言应该有这样的特性: 45 | 46 | 语法有点像C , 这样大家容易接受 47 | 没有C语言那样的指针 48 | 再也不要考虑内存管理了, 实在受不了了 49 | 真正的可移植性, 编写一次, 到处运行 50 | 面向对象 51 | 类型安全 52 | 还有,我们要提供一套高质量的类库, 随语言发行。 53 | 54 | 我想把这个语言命名为C++-- , 即C++减减, 因为我想在C++的基础上改进,把它简化。 55 | 56 | 后来发现不行, 设计理念差别太大。 57 | 58 | 干脆重启炉灶。 59 | 60 | 我看到门口的一棵橡树, 就把这个语言叫做Oak。 61 | 但是后来发布的时候, 发现Oak已经被别人用了, 我们讨论很久, 最终决定把这门新的语言叫做 Java。 62 | 63 | 为了实现跨平台, 我们在操作系统和应用程序之间增加了一个抽象层: Java 虚拟机 64 | 65 | 用Java写的程序都跑在虚拟机上, 除非个别情况, 都不用看到操作系统。 66 | 67 | 3 68 | ## 一鸣惊人 69 | 70 | 为了吸引更多的人加入我们的新领地, 我们决定搞一个演示, 向大家展示Java 的能力。 71 | 72 | 出世未久的Java其实还远不完善。 搞点什么好呢? 73 | 74 | 我们把眼光盯上了刚刚兴起的互联网, 1995年的网页简单而粗糙, 缺乏互动性。 于是我们在浏览器上弄了个小插件, 把java 运行环境放了上去。 75 | 76 | 然后在上面开发了一个图形界面的程序(Applet), 让它看起来美轮美奂, 震撼人心。 77 | 78 | 每一个看到他的程序员都会发出“Wow”的惊叹 !为之倾倒。 79 | 80 | Java 活了! 81 | 82 | 通过Applet , 无数的程序员看到了Java这门语言,了解了这门语言特性以后, 很多无法忍受C帝国暴政的程序员, 很快加入了我们, 我们的领地开始迅速扩大。 83 | 84 | 连C语言帝国里的一些商业巨头也纷纷来和我们合作, 其中就包括Oracle , 微软这样的巨头 , 微软的头领Bill Gates还说 :这是迄今为止设计的最好的语言! 85 | 86 | 但是Bill Gates非常的不地道, 买了我们的Java 许可以后,虽然在自家的浏览器上也支持Applet, 但是他们却偷偷的试图修改Java , 想把Java绑死在自家的操作系统上赚钱, Java会变的不可移植。 87 | 88 | 这是我们难于忍受的, 我们和微软发起了一场旷日持久的游击战争, 逼着微软退出了Java领域, 开发了自己的.NET , 这是后话。 89 | 90 | 4 91 | ## 开拓疆土 92 | 93 | 从1995年到1997年,我们依靠 Java 不断的攻城略地, 开拓疆土,我们王国的子民不断增加, 达到了几十万之众, 已经是一个不可忽视的力量了。 94 | 95 | 但是大家发现, Java除了Applet, 以及一些小程序之外, 似乎干不了别的事情。 96 | 97 | C帝国的人还不断的嘲笑我们慢, 像个玩具。 98 | 99 | 到了1998年, 经过密谋, 我们Java 王国决定派出三只军队向外扩展: 100 | Java 2 标准版(J2SE): 去占领桌面 101 | Java 2 移动版(J2ME): 去占领手机 102 | Java 2 企业版(J2EE): 去占领服务器 103 | 104 | 其中的两只大军很快败下阵来。 105 | 106 | J2SE 的首领发现, 开发桌面应用的程序员根本接受不了Java, 虽然我们有做的很优雅的Swing 可以开发界面, 但是开发出的界面非常难看, 和原生的桌面差距很大。 尤其是为了运行程序还得安装一个虚拟机, 大家都受不了。 107 | 108 | J2ME也是, 一直不受待见, 当然更重要的原因是乔布斯还没有重新发明手机, 移动互联网还没有启动。 109 | 110 | 失之东隅,收之桑榆, J2EE赶上了好时候, 互联网大发展, 大家忽然发现, Java简直是为写服务器端程序所发明的! 111 | 112 | 强大, 健壮, 安全, 简单, 跨平台 ! 113 | 114 | 在J2EE规范的指导下, 特别适合团队开发复杂的大型项目。 115 | 116 | 我们授权BEA公司第一个使用J2EE许可证, 推出了Weblogic, 凭借其集群功能, 第一次展示了复杂应用的可扩展性和高可用性。 117 | 118 | 这个后来被称为中间件的东西把程序员从事务管理,安全管理,权限管理等方面解放出来, 让他们专注于业务开发。 这立刻捕获了大量程序员的心。 119 | 120 | 很快Java 王国的子民就达到数百万之众。 121 | 122 | 榜样的力量是无穷的, 很快其他商业巨头也纷纷入场, 尤其是IBM,在Java 上疯狂投入,不仅开发了自己的应用服务器 Websphere, 还推出了Eclipse这个极具魅力的开源开发平台。 123 | 124 | 当然IBM利用java 获得了非常可观的效益, 软件+硬件+服务 三驾马车滚滚向前, 把IBM推向了一个新的高峰。 125 | 126 | 5 127 | ## 帝国的诞生 128 | 129 | 大家也没有想到,除了商业巨头以外, 程序员们也会对Java王国 这么热爱, 他们基于Java 开发了巨多的平台,系统,工具,例如: 130 | 131 | 构建工具: Ant,Maven, Jekins 132 | 133 | 应用服务器: Tomcat,Jetty, Jboss, Websphere, weblogic 134 | 135 | Web开发: Struts,Spring,Hibernate, myBatis 136 | 137 | 开发工具: Eclipse, Netbean,intellij idea, Jbuilder 138 | 。。。。等等等等。。。。 139 | 140 | 并且绝大部分都是开源的 ! 141 | 142 | 微软眼睁睁的看着服务器端的市场被Java 王国占据, 岂能善罢甘休? 他们赶紧推出.NET来对抗, 但我们已经不在乎了, 因为他的系统是封闭的,所有的软件都是自家的: 143 | 开发工具是Visual Studio, 应用服务器是IIS, 数据库是SQL Server,只要你用.NET,基本上就会绑定微软。 144 | 145 | 另外他们的系统只能运行在Windows服务器上, 这个服务器在高端市场的占有率实在是太低了。 146 | 147 | 2005年底, 一个新的王国突然崛起, 他们号称开发效率比java 快5-10倍, 由此吸引了大批程序员前往加盟。 148 | 149 | 这个新的王国叫做Ruby on Rails, 它结合了PHP体系的优点(快速开发)和Java体系的优点(程序规整), 特别适合快速的开发简单的Web网站。 150 | 151 | 虽然发展很快, 但没有对Java 王国产生实质性的威胁, 使用Ruby on Rails搭建大型商业系统的还很少。 152 | 153 | 除了Ruby on Rails ,还有PHP, Python , 都适合快速开发不太复杂的Web系统。 但是关键的,复杂的商业系统开发还是Java 王国的统治之下。 所以我们和他们相安无事。 154 | 155 | 2006年, 一只叫Hadoop的军队让Java王国入侵了大数据领域, 由于使用Java 语言, 绝大多数程序员在理解了Map/Reduce , 分布式文件系统在Hadoop中的实现以后, 很快就能编写处理处理海量数据的程序, Java 王国的领地得到了极大的扩展。 156 | 157 | 2008年, 一个名叫Android 的系统横空出世, 并且随着移动互联网的爆发迅速普及, 运行在Android之上的正是Java ! 158 | 159 | Java 王国在Google的支持下, 以一种意想不到的方式占领了手机端, 完成了当年J2ME 壮志未酬的事业 ! 160 | 161 | 到今年为止, 全世界估计有1000万程序员加入了Java王国,它领土之广泛, 实力之强大, 是其他语言无法比拟的。 162 | 163 | Java 占据了大部分的服务器端开发,尤其是关键的复杂的系统, 绝大多数的手机端, 以及大部分的大数据领域。 164 | 165 | 一个伟大的帝国诞生了。 166 | 167 | 这个帝国能生存多久? 谁会摧毁这个庞大的帝国呢? 168 | 169 | 我不知道, 你呢? 170 | 171 | -------------------------------------------------------------------------------- /TCP-IP 之 大明王朝邮差: -------------------------------------------------------------------------------- 1 | ## TCP/IP 之 大明王朝邮差 2 | 3 | 原创: 刘欣 码农翻身 4 | 5 | 前言: 本文主要想说一下TCP的知识, 比喻有不恰当之处,敬请包涵。 6 | 7 | 大明王朝天启四年, 清晨。 8 | 9 | 10 | 11 | 天色刚蒙蒙亮,我就赶着装满货物的马车来到了南城门, 这里是集中处理货物的地方 , 一队一队的马车都来到这里, 城头的士兵带着头盔,身披盔甲, 手持长枪, 虎视眈眈的注视这下面的动静。 12 | 13 | 14 | 城门口的大棚里乱哄哄的,是一群人围在一起赌钱, 这些家伙都穿着同样的衣服, 前胸和后背写着三个大字 “TCP邮差” 15 | 16 | 我知道这就是我要找的人, 他们会帮我把货物发出去。 17 | 18 | 19 | 20 | 我下了车,在大棚里四处查看, 找到一个无聊的坐着独自喝闷酒的小伙子。 21 | 22 | 23 | 24 | "邮差小哥 ,帮我把这车货发了呗" 25 | 26 | 27 | 28 | 小伙子懒洋洋的站起来说: “你从哪儿来,要到哪儿而去啊?” 29 | 30 | 31 | 32 | 我赶紧拿出写好的地址说: ”我住在咱们城里北拐街224号, 要发一车货物到内乡县衙“ 33 | 34 | “内乡县衙有很多门, 你的货进那个门啊?” 邮差小哥接着问。 35 | 36 | 37 | 38 | “出发的时候老板给我说了, 发到80号门 。” 39 | 40 | 41 | 42 | 邮差小哥说: “走吧, 咱们到前面去。” 43 | 44 | 45 | 46 | 大棚的前面是一大批开阔地, 可能我们来的早 , 现在只有我,邮差小哥, 当然,还有我的马车。 47 | 48 | 49 | 50 | “你等等, 我先给内乡县衙建立个连接 ”邮差说着, 吹了个口哨, 一匹马跑了过来。 51 | 52 | 53 | 54 | 他拿起毛笔在一张纸写了一封信: 55 | “县衙县衙, 我是京城, 我想和你建立连接, 我的序号1024 , 收到请回话! ” 56 | 57 | 信封上写着: 58 | 发货地:京城北拐街224号 59 | 收货地:内乡县衙, 80号门 60 | 61 | 然后把这这个纸放到了马背上的褡裢里, 拍了拍马屁股: “快走吧。” 62 | 63 | 64 | 65 | 过了两个时辰, 那匹马回来了, 邮差掏出了马运回来的那封信, 上面写着: 66 | “京城京城,收到了你的信, 你的信里边有个序号是1024,对不对? 同意建立咱们的连接, 我这边序号是2048” 67 | 68 | 69 | 70 | 邮差喜形于色 : “ 看看, 连接快要建立了, 我再给他们发一封信就行了” 71 | ”县衙县衙, 我收到你的确认信了, 也看到了你的序号是2048, 我开始发货了” 72 | 73 | 74 | 75 | 我问他: “这就是连接吗, 我没看见你扯一条线把京城和县衙连起来啊” 76 | 77 | 78 | 79 | 邮差说: “这你就不懂了吧,这就是TCP连接, 是虚拟的, 连接的状态信息并不会在路上保存; 相反, 连接的状态信息是在两端维持的, 也就是在我这里和县衙那里一起维持的。 ” 80 | 81 | 82 | 83 | “那你们为啥要发三封信呢? ” 84 | 85 | 86 | 87 | “这就是三次握手啊, 我给你分析一下啊, 这三次握手主要是为了验证我这边和县衙那边的发信/收信能力没问题, 这样就证明连接是通的, 可以正式发货了。” 88 | 89 | 90 | 91 | 第一次握手:京城发信,县衙收到了,此时县衙就会明白:京城发信能力和自己的收信能力是没问题的。  92 | 93 | 94 | 95 | 第二次握手:县衙发信,京城收到了,此时京城就会明白:京城的发信和收信都是好的, 县衙的发信和收信也都是没问题的。 要不然收不到县衙的回信 , 但是县衙还不知道自己的发信功能如何?所以需要第三次握手: 96 | 97 | 98 | 99 | 第三次握手:京城发信,县衙收到了,此时京城已经确认,双发的收信,发信都是没问题的, 这次回应的目的只是消除县衙对自己的发信功能和京城的收信功能的担忧而已。  100 | 101 | 102 | 103 | 说实在的, 我有点晕, 邮差小哥说 : “你多琢磨琢磨就明白了。” 104 | 105 | 106 | 107 | 我问他: “你这么辛苦的建立连接, 难道不亲自去送货吗?” 108 | 109 | 邮差说:“ 我才不去呢! 本朝新皇登基以来,整天像木匠一样做木工,不理朝政, 导致民不聊生, 大片田地荒芜, 强盗,野兽横行, 早就没有人敢冒着风险去送货了。所以内阁的那帮大臣们就想了个招,修建四通八达的官道, 让马,驴这些牲畜去送货, 即使被老虎吃掉也没啥损失, 天朝还是挺以人为本的。” 110 | 111 | 112 | 113 | “那这些马怎么知道把我的货送的内乡县衙啊” 114 | 115 | 116 | 117 | “不用担心, 它们都是训练过的, 会沿着官道走,在每一个每个岔路口朝廷都会修建一个驿站, 马累了可以吃草喝水休息, 更关键的是,每个驿站的衙役会看看我刚才写的信 ,他们知道路, 然后把马领到一个新的正确的官道,继续走, 最终就能到内乡县衙。 对了, 大家给这些驿站起来个别名:路由器” 118 | 119 | 120 | 121 | “万一马跑丢了, 或者被老虎吃掉,到不了,或者回不来怎么办?” 122 | 123 | 124 | 125 | “那就是我们TCP邮差要干的事儿了, 你马上就会看到, 我来看看你的货, 哎啊, 你这个柜子太大了, 一匹马驮不走, 得分成小包裹, 一个一个运” 126 | 127 | 128 | 129 | 我没办法, 只好把一件大货物拆开, 分成小包裹。 130 | 131 | 132 | 133 | “ 给每个包裹编个号吧” 邮差说到。 “这样到了内乡县衙他们就能组装起来,原样恢复了” 134 | 135 | 136 | 137 | 我突然想到一个严重问题:“万一马被强盗抢走了。我这个柜子的一条腿岂不就丢了 ” 138 | 139 | 140 | 141 | 邮差见怪不怪: “没办法, 内阁的大人们说了, 这种情况, 就重新发送那一个包裹。” 142 | 143 | 144 | 145 | 擦, 我心头有一万头羊驼跑过: 这帮大人们真是站着说话不腰疼啊, 万一柜子的腿儿丢了, 我还得重做啊。 146 | 147 | 148 | 149 | 邮差把包裹按编号摆成一列, 1, 2, 3, ...... 10 ,一共10个包裹。 150 | 151 | 152 | 153 | “按规定我们每次最多发3个包裹,按序号发, 先发 1, 2, 3号包裹” 邮差说着叫来3匹马, 装上货,马一溜烟的跑掉了。 154 | 155 | 156 | 157 | 我在那里提心吊胆的等着,生怕一个包裹丢了。 158 | 159 | 160 | 161 | 可是怎么知道包裹是不是到了县衙了呢。 162 | 163 | 164 | 165 | 邮差似乎看出了我的心思, 从怀里掏出一个沙漏说: 如果漏完了, 县衙还没给咱们确认, 那就是丢了, 只有重发了。 166 | 167 | 168 | 169 | 过了一个时辰, 我期盼的县衙的马终于来了, 里边的信里说: 1号包裹收到了。 170 | 171 | 172 | 173 | “好了” 邮差说, “县衙确认收到了 1号包裹, 咱们可以再发一个了”, 说着叫来一匹马, 把第4号包裹发了出去。 174 | 175 | 176 | 177 | 我现在有点理解了, 邮差的做法是每次只保证有3个包裹发出去并且没有确认 178 | 179 | 180 | 181 | 又过了一会, 县衙一下子来了3匹马, 带来了2,3,4号包裹的确认。 182 | 183 | 184 | 185 | 邮差说: " 看来你的运气还不错, 我在把5,6,7 号发出去“ 说着他把沙漏掉了个个, 重新开始计时。 186 | 187 | 188 | 189 | 5号包裹的确认很快来了, 邮差又把8号发了出去, 这样已经发送但是没有确认的包裹还是三个。 190 | 191 | 192 | 193 | 现在6,7,8号包裹都发出去了, 可是6号包裹的确认迟迟不来, 我心急如焚。 194 | 正在此时, 沙漏漏完了, 我不安的向邮差看去。 195 | 196 | 197 | 198 | 他倒是满不在乎:“ 哎呀, 超时了,有可能是运送6号包裹的马被老虎吃了, 县衙没收到” 199 | 200 | 201 | 202 | “那怎么办啊” 我焦急的问。 203 | 204 | 205 | 206 | “我们只好从6号包裹开始重新发送了, 6号包裹恰好是柜子的一条腿儿, 回去给你老板说说, 再做做个柜子腿儿吧, 一定要保证和之前发出去的一模一样。” 207 | 208 | 209 | 210 | 我问他: “那7,8号包裹呢? 县衙收到没有?” 211 | 212 | 213 | 214 | “我们现在还不知道,如果收到了, 他们会暂时存下来。 如果没收到, 那还得像6号包裹一样,继续重发。” 215 | 216 | 217 | 218 | 我的忍耐力到了极限, 真想跳起来揍邮差一顿。 219 | 220 | 221 | 222 | 冷静下来, 我想了想说:“不对,你为什么一下发了3个包裹, 你不能发一个等着确认一个吗? 我要告你去 。” 223 | 224 | 225 | 226 | 邮差说: “随便你了, 反正你是告不赢的, 这是内阁首辅大人确定的, 我们用的叫滑动窗口协议, 如果窗口N=1 , 即发一个等着确认一个, 那样就太慢了, 我这个邮差也不能一直被你占用, 我们把N的值设大一点, 例如N=3, 就是为了能够像流水线那样做事, 一边发包裹, 一边收确认, 这样快一点。” 227 | 228 | 229 | 230 | 没办法,只好回去找老板做柜子腿儿, 这耽误了很多时间。 231 | 232 | 233 | 234 | 邮差把6号包裹又发了出去, 再次重新计时。 235 | 236 | 237 | 238 | 6号包裹的确认还是没有收到! 7号的确认也没收到, 但是8号包裹的确认先收到了! 239 | 240 | 241 | 242 | 邮差说: “恩, 不错,6,7号的确认包裹估计是在路上丢了, 没关系, 只要县衙说收到了8号包裹, 暗含的意思就是 6, 7 号都收到了。 要不然他们不会发8号的确认。” 243 | 244 | 245 | 246 | 接下来就发9,10号包裹, 这次还行, 总算没丢, 终于把整个柜子全发出去了。 247 | 248 | 249 | 250 | 内乡县衙那边也把柜子给组装了起来。 我的任务总算完成了。 251 | 252 | 253 | 254 | 后来我得知, 县衙其实是收到了第6号包裹,只是他们的发给京城的确认包裹在路上给弄丢了, 我们没收到, 导致我们重新发了一份。 255 | 256 | 257 | 258 | 我算是明白了这所谓的TCP, 无非就是在那些不可靠马匹运输的基础上建立一个可靠的发送办法, 基本上就是失败重发, 受苦的还是我们这些底层老百姓。 259 | 260 | 261 | 262 | 我给邮差付了2两银子作为费用 , 拉着马车,头也不回的走了。 263 | 264 | 265 | 266 | 只听到邮差在后边喊:“ 欢迎再来, 内阁首辅正在研究新的协议呢, 下次一定要来试试啊。” 267 | 268 | 269 | 270 | 我没理他, 因为我再也不想来到这个鬼地方了! 271 | 272 | 273 | 公众号: 码农翻身 274 | 275 | “码农翻身”公众号由工作15年的前IBM架构师创建,分享编程和职场的经验教训。 276 | 277 | -------------------------------------------------------------------------------- /CPU阿甘.md: -------------------------------------------------------------------------------- 1 | ## CPU阿甘 2 | 3 | 原创: 老刘 码农翻身 4 | 5 | ![1](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6UKrH40NicwIgib1gN4WOC8bWYicvR0RB6DfwPZax49yNUerpNDLaWsQO73tgibKZvGPfatZPFPOxVibv9g/640?wx_fmt=jpeg&tp=webp&wxfrom=5) 6 | 7 | 前言 8 | 9 | 上帝为你关闭了一扇门,就一定会为你打开一扇窗 10 | 这句话来形容我最合适不过了。 11 | 12 | 我是CPU, 他们都叫我阿甘, 因为我和《阿甘正传》里的阿甘一样, 有点傻里傻气的。 13 | 14 | 上帝把我制造出来, 给我了一个很小的脑容量, 为数不多的寄存器能临时的记一点东西, 但是上帝给我打开了一扇特别的窗户, 那就是像阿甘一样,跑的飞快。 15 | 16 | 到底有多快呢? 我这么比喻一下吧, 我的工作都是以纳秒为单位的, 你们人间的一秒, 我可能已经做了1000,000,000 (10亿)次动作了。 17 | 18 | 相比而言, 内存比我慢100倍, 硬盘比我慢1000多万倍, 你说我快不快? 19 | 20 | 启动 21 | 22 | 我住在一个机箱里,每天早上一阵电流把我叫醒, 还夹杂着嗡嗡的声音, 我知道我忠实的护卫电风扇又开始工作了, 我特别怕热, 又运行的飞快, 如果没有电风扇给我降温, 我很快就会生病, 生病的后果很严重, 那就是我的伙伴们像内存了,硬盘了。。全部都要罢工了, 没有我这个系统就会陷入的一片死寂。 23 | 24 | 我听说有些CPU的福利很好,竟然待在恒温恒湿,一尘不染的托管机房里,让我好生羡慕。 25 | 26 | 我的脑容量很小, 所以醒来后只想起了我的创造者告诉我的几件事情 : 27 | 1. 你的工作就是运行指令 28 | 2. 你不能保存指令, 你的指令全在内存里 29 | 3. 你的第一条指令在内存的最顶端处0xFFFFFFF0 30 | 31 | 那还有什么可说的, 赶紧打电话给内存要指令,电话通过系统总线, 还得通过I/O桥电话局需要转接一下, 再通过存储总线接通 内存。 32 | 33 | "哥们, 把这个地址处的指令给我说一下吧" 34 | 35 | "你是谁?" 内存竟然把我忘了, 当然,他断了电和我一样,失忆了。 36 | 37 | "我是阿甘啊, 我们经常聊天来着, 你忘了?" 38 | 39 | 内存磨磨唧唧半天才把数据发了过来(比我慢100倍啊), 这是一条跳转指令, 我立刻回忆起来了, 这是我的老朋友BIOS 等着我去运行他那一堆指令呢。 40 | 41 | 我给BIOS打电话: “老弟,今天干点啥?” 42 | 43 | “阿甘,早上好 " BIOS从不失忆,把所有人都记得清清楚楚 “ 还不是老一套啊,无非做一下系统的自检, 看看内存,硬盘,显卡等这些老伙计们有没有问题, 有问题的话用小喇叭提示一下主人 ” 44 | 45 | 这些过程我已经轻车熟路了, 很快搞定, 像往常一样,没有问题, 我还把一个叫做中断向量表的东西给弄好了, 我知道一会而要用 46 | 47 | 这些东西都搞完了,BIOS果然告诉: "阿甘, int 0x19" 48 | 49 | 我赶紧去刚弄好的中断向量表中去查第19号, 顺藤摸瓜又找到对应0x19的一大堆指令。 50 | 51 | 执行吧, 这堆指令把将磁盘的第一扇区(磁盘最开始的512字节)运到内存的0X0000:0X7C00处,然后我就从此处接着执行。 52 | 53 | 我想起来了, 接下来有一大堆精巧的指令把迷迷糊糊的操作系统从硬盘中唤醒, 运输到内存中来。 54 | (此处实在是复杂, 略去10万字。。。。) 55 | 56 | 你看这就是为啥他们叫我阿甘, 我做事飞快,但非得别人告诉去哪里执行才行, 要不然我就只会坐在那里无所适从。 57 | 58 | 运行 59 | 60 | 操作系统一旦进入内存,立刻就是老大, 所有人都得听他指挥。 61 | 62 | 我也发现我的周围出现了一个屋子:进程屋 63 | 屋里堆着一大堆东西, 什么进程描述信息包裹了, 进程控制信息包裹了, 我都不太关心, 我只关心最最重要的两件东西: 64 | 1. 我工作必备的寄存器, 就放在我面前的工作台上。 65 | 2. 程序计数器, 我用它记住我要执行的下一条指令地址。 66 | 67 | "阿甘, 别来无恙啊" , 操作系统对我还是挺不错的, 先给我打招呼。 68 | 69 | "Linux老大, 今天有什么活啊", 我每次都表现的积极主动。 70 | 71 | "来,把这个hello world 程序给运行了" 72 | 73 | Hello world 程序还在硬盘上睡着呢, 得先把他也装载到内存里, 要不然我怎么执行啊。 74 | 75 | 于是我就拿起电话打给硬盘, 电话通过系统总线来到IO桥电话局, 再转接到IO总线,这才来到硬盘这里。 76 | 77 | 我在电话里请他把数据给我运过来, 然后我就无所事事的坐在那里等。 78 | 79 | Linux 老大立刻就怒了 : 阿甘, 告诉你多少次了, 你小子怎么还在等硬盘给你发数据! 80 | 81 | 是的, 我忘了一件事,硬盘比我慢太多了, 我执行一条指令大概是1ns ,在用来读磁盘的16ms里, 我能潜在的执行1600多万条指令啊。 82 | 83 | 我感到深深的愧疚, 赶紧拿起电话打给硬盘 : 哥们, 按我们之前商量好的,用直接内存访问(DMA)啊, 你直接把数据装载到内存吧, 不用经过我了, 装载完成以后给我发个信号。 84 | 85 | "这还差不多" Linux 老大心情好了些 86 | “阿甘,数据还没来, 别闲着, 这有一个菲波那切数列数列, 来算一下吧” 87 | 88 | "肥波纳妾数列? 这名字好古怪,老大, 其实你也知道, 我脑子小,懒得去理解那是啥意思, 你把进程屋切换下,把程序计数器设置好,指向下一条指令, 我一条条指令执行就得了“ 我挺没追求的。 89 | 90 | "真是个阿甘啊! ”老大感慨到。 91 | 92 | 我所处的进程屋立刻发生了变化(当然,这也是我辅助Linux老大干的), 各种包裹的信息都变了, 尤其是寄存器和程序计数器。 93 | 94 | 于是我就开始计算这个什么纳妾数列 ,但是这个数列似乎无穷无尽, 哪个无脑子的程序员写了个无限循环吧。 95 | 96 | 正在这时, 我便收到了一个电话, 说是Helloworld的数据已经装载到内存了, 让我去处理。 97 | 98 | 我放下手中的活, 保存好现场, 就去处理那个Helloworld, 果然数据已经都好了, 那就切换过去运行吧。 99 | 100 | 其实老大并不知道, 任何人,只要你运行了相当多的数量的指令以后, 你都能悟到这些程序的秘密。 101 | 我CPU阿甘虽然傻傻的, 但也架不住执行这数以万万亿的指令给我的熏陶啊。 102 | 103 | 这个秘密就是:程序都是由顺序,分支,循环来组成的。 其实分支和循环在我看来都是跳转而已。 104 | 105 | 所以我的工作就是打电话问内存要一条指令, 执行这个指令, 如果是个跳转指令的话,我就问内存要跳转的目标地址的那一条指令, 继续执行, 生活就是这么简单。 106 | 107 | 奥对了, 当然也有复杂的, 就是函数调用, 我得和内存紧密配合才能完成。 这个咱下回再说。 108 | 109 | 新装备:缓存 110 | 111 | 提到内存, 这真是我的好哥们, 没有他,我几乎什么事儿都干不成, 更重要的是他比硬盘快的多, 读取一次数据, 只需要 100 纳秒左右。 这样我们俩说起话来就轻松多了。 112 | 113 | 每次他都说: "阿甘, 幸亏有你给我聊天, 要不然我肯定被活活的闷死不可, 那个硬盘说话是在太慢了" 114 | 115 | "它为啥那么慢?" 我每次都问 116 | 117 | "硬盘是个机械是的玩意, 一个磁头在一碟高速旋转的磁片上挪来挪去,光定位就慢死了" 118 | 119 | "那主人为什么要用硬盘?" 120 | 121 | "人家虽然慢, 但是不怕停电, 哪像你和我,一停电全部都失去记忆了。" 122 | 123 | 确实是, 人不能把好事都占全了啊。 124 | 125 | 我的指令中有些完全用我的寄存器就能完成, 但是有很多都需要读写内存的数据, 再加上所有的指令都在内存中存着, 虽然它只比我慢个100倍, 但指令多了我还是有点受不了。 126 | 127 | 我给内存说:"哥们, 你能不能再快点!" 128 | 129 | 内存说: 拜托, 这已经是我的极限了, 阿甘, 你自己再想想办法吧 ! 我给你说啊, 我留意了你最近访问的指令和数据, 我发现了个规律“ 130 | 131 | "啥规律?" 132 | 133 | "比如说吧, 你访问了我一个内存位置以后过不多久还会多次访问, 还有,一个内存位置被访问了, 附近的位置很快也会访问到" 134 | (码农翻身注: 这其实叫程序的局部性原理) 135 | 136 | 我还以为是啥规律, 其实我早就注意到了。 137 | 138 | "这有啥用啊?” 139 | 140 | "既然你经常访问同一块区域的东西, 你想想如果把这些东西缓存在你那里会怎么样.... " 141 | 142 | 我一想有道理啊! 加个缓存试试! 143 | 144 | 从此以后,我每次读写指令和数据, 都问缓存要, 缓存没有才给内存打电话。 145 | 146 | 果然, 由于局部性原理的存在, 我发现的确是快了不少啊。 147 | 148 | 当然也有缺点, 那就是Linux老大在做程序切换的时候, 缓存就会失效,因为两个程序之间没什么联系,局部性原理不起作用, 所以需要重建缓存。 149 | 150 | 151 | 自我提升:流水线 152 | 153 | 缓存让我的工作更有效率, 得到了Linux老大的表扬:"阿甘, 我看你很聪明嘛, 都会用缓存了" 154 | 155 | "我哪有那么聪明,都是内存的点子。老大,不过我学会了一个重要的东西 :当你改变不了别人的话,抱怨也没用, 还是先改变一下自己吧" 156 | 157 | "挺有哲理的吗, 希望你明天重启后还能想起来" Linux老大笑话我。 158 | 159 | "我最近又发现了一个问题, 正苦恼着呢, 你看我有四只手, 第一只手负责打电话问内存要指令, 第二只手翻译指令, 第三只手真正执行, 第四只手有时候还得把结果写回内存。 问题是, 我发现经常只有一只手在忙活, 其他都在闲着, 你看第一只手取指令, 其他手只能等着。 第二只手翻译指令的时候,其他三只也得等“ 160 | 161 | "看来以后我们不能叫你阿甘了, 你已经开始思考了" Linux老大笑了 162 | 163 | “这问题好解决, 给你举个例子,你听说过洗车没有? 和你差不多, 也是先喷水, 再打洗洁剂, 再擦洗, 最后烘干, 但人家的工作方式和你不一样,人家是流水线作业, 你想想, 一辆车在烘干的时候, 后边是不是还有三辆车,分别在喷水, 打清洁剂 和擦洗 , 每个步骤都不会空闲。 ” 164 | 165 | "这么简单的道理我怎么都没有想到呢? 我也可以搞个流水线啊, 这样每只手都利用起来了" 166 | 167 | 别人都说我们高科技, 但其实原理都蕴含在生活之中啊。 168 | 169 | 有了缓存和流水线的帮助, 让我的工作大大的加快了,大家都对我刮目相看。 他们想给我起个新名字:超人 , 不过我还是更喜欢 他们叫我“阿甘”, 多亲切。 170 | 171 | 尾声 172 | 173 | 我一丝不苟,兢兢业业的运行指令, 时不时和伙伴们聊天, 很快一天就过去了, 又到了晚上,我知道关机的时刻到了, 赶紧挨个给他们道别。 174 | 175 | 很快那些让我兴奋的电流消失了,风扇的嗡嗡声也没有了, 我再也无法打出电话,整个世界沉寂了。 176 | 177 | 明天将会是新的一天。 178 | 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /我是一个线程.md: -------------------------------------------------------------------------------- 1 | ## 我是一个线程 2 | 3 | #### 原创: 老刘 码农翻身 4 | 5 | ## 第一回 初生牛犊 6 | 7 | 我是一个线程,我一出生就被编了个号:0x3704,然后被领到一个昏暗的屋子里,在这里我发现了很多和我一模一样的同伴。 8 | 9 | 我身边的同伴0x6900 待的时间比较长,他带着沧桑的口气对我说:“我们线程的宿命就是处理包裹。把包裹处理完以后还得马上回到这里,否则可能永远回不来了。” 10 | 11 | 我一脸懵懂,“包裹,什么包裹?” 12 | 13 | “不要着急,马上你就会明白了,我们这里是不养闲人的。” 14 | 15 | 果然,没多久,屋子的门开了, 一个面貌凶恶的家伙吼道:“0x3704 ,出来!” 16 | 17 | 我一出来就被塞了一个沉甸甸的包裹,上面还附带着一个写满了操作步骤的纸。 18 | 19 | “快去,把这个包裹处理了。” 20 | 21 | “去哪儿处理?” 22 | 23 | “跟着指示走,先到就绪车间。” 24 | 25 | 果然,地上有指示箭头,跟着它来到了一间明亮的大屋子,这里已经有不少线程了,大家都很紧张,好像时刻准备着往前冲。 26 | 27 | 我刚一进来,就听见广播说:“0x3704,进入车间。” 28 | 29 | 我赶紧往前走,身后有很多人议论。 30 | 31 | “他太幸运了,刚进入就绪状态就能运行。” 32 | 33 | “是不是有关系?” 34 | 35 | “不是,你看人家的优先级多高啊,唉!” 36 | 37 | 前边就是车间,这里简直是太美了,怪不得老线程总是唠叨着说:“要是能一直待在这里就好了。” 38 | 39 | 这里空间大,视野好,空气清新,鸟语花香,还有很多从来没见过的人,像服务员一样等着为我服务。 40 | 41 | 他们也都有编号,更重要的是每个人还有个标签,上面写着:硬盘、数据库、内存、网卡…… 42 | 43 | 我现在理解不了,看看操作步骤吧。 44 | 45 | 第一步:从包裹中取出参数。 46 | 47 | 打开包裹,里边有个HttpRequest对象,可以取到userName、 password两个参数。 48 | 49 | 第二步:执行登录操作。 50 | 51 | 奥,原来是有人要登录啊,我把userName、password交给数据库服务员,他拿着数据,慢腾腾地走了。 52 | 53 | 他怎么这么慢?不过我是不是正好可以在车间里多待一会儿?反正也没法执行第三步。 54 | 55 | 就在这时,车间里的广播响了:“0x3704,我是CPU,记住你正在执行的步骤,然后马上带着包裹离开!” 56 | 57 | 我慢腾腾地开始收拾。 58 | 59 | “快点,别的线程马上就要进来了。” 60 | 61 | 离开这个车间,又来到一个大屋子,这里有很多线程在慢腾腾地喝茶,打牌。 62 | 63 | “哥们,你们没事干了?” 64 | 65 | “你新来的吧,你不知道我在等数据库服务员给我数据啊!据说他们比我们慢好几十万倍,在这里好好歇吧。” 66 | 67 | “啊? 这么慢!我这里有人在登录系统,能等这么长时间吗?” 68 | 69 | “放心,你没听说过人间一天,CPU一年吗?我们这里是用纳秒、毫秒计时的,人间等待一秒,相当于我们好几天呢,来得及。” 70 | 71 | 干脆睡一会吧。不知道过了多久,大喇叭又开始广播了:“0x3704,你的数据来了,快去执行!” 72 | 73 | 我转身就往CPU车间跑,发现这里的门只出不进! 74 | 75 | 后面传来阵阵哄笑声:“果然是新人,不知道还得去就绪车间等。” 76 | 77 | 于是赶紧到就绪车间,这次没有那么好运了,等了好久才被再次叫进CPU车间。 78 | 79 | 在等待的时候,我听见有人小声议论: 80 | 81 | “听说了吗,最近有个线程被kill掉了。” 82 | 83 | “为啥啊?” 84 | 85 | “这家伙赖在CPU车间不走,把CPU利用率一直搞成100%,后来就被kill掉了。” 86 | 87 | “Kill掉以后弄哪儿去了?” 88 | 89 | “可能被垃圾回收了吧。” 90 | 91 | 我心里打了个寒噤,赶紧接着处理,剩下的动作快多了,第二步登录成功。 92 | 93 | 第三步:构建登录成功后的主页。 94 | 95 | 这一步有点费时,因为有很多HTML需要处理,不知道代码谁写的,处理起来很烦人。 96 | 97 | 我正在紧张的制作HTML呢, CPU又开始叫了: 98 | 99 | “0x3704,我是CPU ,记住你正在执行的步骤,然后马上带着包裹离开!” 100 | 101 | “为啥啊?” 102 | 103 | “每个线程只能在CPU上运行一段时间,到了时间就得让别人用了,你去就绪车间待着,等着叫你吧。” 104 | 105 | 就这样,我一直在“就绪——运行”这两个状态中不知道轮转了多少次, 终于按照步骤清单把工作做完了。 106 | 107 | 最后顺利地把包含html的包裹发了回去。至于登录以后干什么事儿,我就不管了。马上就要回到我那昏暗的房间了,真有点舍不得这里。不过相对于有些线程,我还是幸运的,他们运行完以后就被彻底地销毁了,而我还活着! 108 | 109 | 回到了小黑屋,老线程0x6900问: 110 | 111 | “怎么样?第一天有什么感觉?” 112 | 113 | “我们的世界规则很复杂,首先你不知道什么时候会被挑中执行;第二,在执行的过程中随时可能被打断,让出CPU车间;第三,一旦出现硬盘、数据库这样耗时的操作,也得让出CPU去等待;第四,就是数据来了,你也不一定马上执行,还得等着CPU挑选。” 114 | 115 | “小伙子理解的不错啊。” 116 | 117 | “我不明白为什么很多线程执行完任务就死了,为什么咱们还活着?” 118 | 119 | “你还不知道?长生不老是我们的特权!我们这里有个正式的名称,叫作线程池!” 120 | 121 | ## 第二回 渐入佳境 122 | 123 | 平淡的日子就这么一天天地过去,作为一个线程,我每天的生活都是取包裹、处理包裹,然后回到我们昏暗的家:线程池。 124 | 125 | 有一天我回来的时候,听到有个兄弟说,今天要好好休息下,明天就是最疯狂的一天。我看了一眼日历,明天是 11月11号。 126 | 127 | 果然,零点刚过,不知道那些人类怎么了,疯狂地投递包裹,为了应付蜂拥而至的海量包裹,线程池里没有一个人能闲下来,全部出去处理包裹,CPU车间利用率超高,硬盘在嗡嗡转,网卡疯狂的闪,即便如此,还是处理不完,堆积如山。 128 | 129 | 我们也没有办法,实在是太多太多了,这些包裹中大部分都是浏览页面,下订单,买、买、买。 130 | 131 | 不知道过了多久,包裹山终于慢慢地消失了。终于能够喘口气,我想我永远都不会忘记这一天。 132 | 133 | 通过这个事件,我明白了我所处的世界:这是一个电子商务的网站! 134 | 135 | 我每天的工作就是处理用户的登录,浏览,购物车,下单,付款。 136 | 137 | 我问线程池的元老0x6900:“我们要工作到什么时候?” 138 | 139 | “要一直等到系统重启的那一刻。”0x6900说。 140 | 141 | “那你经历过系统重启吗?” 142 | 143 | “怎么可能?系统重启就是我们的死亡时刻,也就是世界末日,一旦重启,整个线程池全部销毁,时间和空间全部消失,一切从头再来。” 144 | 145 | “那什么时候会重启?” 146 | 147 | “这就不好说了,好好享受眼前的生活吧……” 148 | 149 | 其实生活还是丰富多彩的,我最喜欢的包裹是上传图片,由于网络慢,所以能在就绪车间、CPU车间待很长很长时间,可以认识很多好玩的线程。 150 | 151 | 比如说上次认识了memecached 线程,他对我说在他的帮助下缓存了很多的用户数据,还是分布式的!很多机器上都有! 152 | 153 | 我问他:“怪不得后来的登录操作快了那么多,原来是不再从数据库取数据了你那里就有啊,哎对了你是分布式的你去过别的机器没有?” 154 | 155 | 他说:“怎么可能!我每次也只能通过网络往那个机器发送一个GET、PUT命令才存取数据而已,别的一概不知。” 156 | 157 | 再比如说上次在等待的时候遇到了数据库连接的线程,我才知道他那里也是一个连接池,和我们的线程池几乎一模一样。 158 | 159 | 他告诉我:“有些包裹太变态了,竟然查看一年的订单数据,简直把我累死了。” 160 | 161 | 我说:“拉倒吧你,你那是纯数据,你把数据传给我以后,我还得组装成HTML,工作量不知道比你大多少倍。” 162 | 163 | 他建议我:“你一定要和memecached搞好关系,直接从他那儿拿数据,尽量少直接调用数据库,这样我们JDBC connection也能活得轻松点。” 164 | 165 | 我欣然接纳:“好啊好啊,关键是你得提前把数据搞到缓存啊,要不然我先问一遍缓存,没有数据,我这不还得找你吗?” 166 | 167 | 生活就是这样,如果你自己不找点乐子,还有什么意思? 168 | 169 | 170 | ## 第三回 虎口脱险 171 | 172 | 前几天我遇到一个可怕的事情,差一点死在外边,回不了线程池了。其实这次遇险我应该能够预想得到才对,真是太大意了。 173 | 174 | 那天我处理了一些从http发来的存款和取款的包裹,老线程0x6900特意嘱咐我:“处理这些包裹的时候一定要特别小心,你必须先获得一把锁,在对账户存款或取款的时候一定要把账户锁住,要不然别的线程就会在你等待的时候趁虚而入,搞破坏,我年轻那会儿很毛糙,就捅了篓子。” 175 | 176 | 为了“恐吓”我, 好心的0x6900还给了我两个表格: 177 | 178 | (1)没有加锁的情况 179 | 180 | ![1](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6UL28zax3ex6mtrMG4Lvibmzv1IoTSW8FiaNJo2oD806exUoNl55ctZuEia1QstPUu5BuJlhB5sEYqyOg/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 181 | 182 | (2)加锁的情况 183 | 184 | ![2](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6UL28zax3ex6mtrMG4LvibmzvibkTlDnOu911biaoqLG8LzXQx63kicqawno1pkVyvaAHnSO9WrhkEnfEA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 185 | 186 | 我看得胆颤心惊,原来不加锁会带来这么严重的事故。从此以后看到存款、取款的包裹就倍加小心,还好没有出过事故。 187 | 188 | 今天我收到的一个包裹是转账,从某著名演员的账户给某著名导演的账户转钱,具体是谁我就不透漏了,数额可真是不小。 189 | 190 | 我按照老线程的吩咐,肯定要加锁啊,先对著名演员的账户加锁,再对著名导演的账户加锁。 191 | 192 | 可我万万没想到的是,还有一个线程,对,就是0x7954, 竟然同时在从这个导演的账户往这个演员的账户转账。 193 | 194 | 于是乎,就出现了这么个情况: 195 | 196 | ![3](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6UL28zax3ex6mtrMG4LvibmzvanJQgprrMtN8fdR6gNPLdtKPQsIzWpklurJJ4ws8k4hGC9p9m2RicsQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 197 | 198 | 刚开始我还不知道什么情况,一直坐在等待车间傻等,可是等的时间太长了,长达几十秒!我可从来没有经历过这样的事件。 199 | 200 | 这时候我就看到了线程0x7954 , 他悠闲地坐在那里喝咖啡,我和他聊了起来: 201 | 202 | “哥们,我看你已经喝了8杯咖啡了,怎么还不去干活?” 203 | 204 | “你不喝了9杯茶了吗?”0x7954回敬道。 205 | 206 | “我在等一个锁,不知道哪个孙子一直不释放!” 207 | 208 | “我也在等锁啊,我要是知道哪个孙子不释放锁我非揍死他不可!”0x7954毫不示弱。 209 | 210 | 我偷偷地看了一眼,这家伙怀里不就抱着我正等的某导演的锁吗? 211 | 212 | 很明显,0x7954也发现了我正抱着他正在等待的锁。 213 | 214 | 很快我们两个就吵了起来,互不相让: 215 | 216 | “把你的锁先给我,让我先做完!” 217 | 218 | “不行,从来都是做完工作才释放锁,现在绝对不能给你!” 219 | 220 | 从争吵到打起来,就那么几秒钟的事儿。更重要的是,我们俩不仅仅持有这个著名导演和演员的锁,还有很多其他的锁,导致等待的线程越来越多,围观的人们把屋子都挤满了。最后事情真的闹大了,我从来没见过的终极大boss“操作系统”也来了。大Boss毕竟见多识广,他看了一眼,哼了一声,很不屑地说: 221 | 222 | “又出现死锁了。” 223 | 224 | “你们俩要Kill掉一个,来吧,过来抽签。” 225 | 226 | 这一下子把我给吓尿了,这么严重啊!我战战兢兢地抽了签,打开一看,是个“活”字。唉,小命终于保住了。 227 | 228 | 可怜的0x7954被迫交出了所有的资源以后,很不幸地被kill掉,消失了。我拿到了导演的锁,可以开始干活了。大Boss“操作系统”如一阵风似的消失了,身后只传来他的声音: 229 | 230 | “记住,我们这里导演>演员,无论任何情况都要先获得导演的锁。” 231 | 232 | 由于这里不仅仅只有导演和演员,还有很多其他人,大Boss留下了一个表格, 里边是个算法,用来计算资源的大小,计算出来以后,永远按照从大到小的方式来获得锁: 233 | 234 | ![4](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6UL28zax3ex6mtrMG4LvibmzveV9z79icNZt6m1URHYhibhb46DvoUw8yt0EUUR1ZNOkZQwOJLPUQZ68A/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 235 | 236 | 我回到线程池,大家都知道了我的历险,围着我问个不停。 237 | 238 | 凶神恶煞的线程调度员把大Boss的算法贴到了墙上。 239 | 240 | 每天早上,我们都得像无节操的房屋中介、美容美发店的服务员一样,站在门口,像被耍猴一样大声背诵: 241 | 242 | “多个资源加锁要牢记,一定要按Boss的算法比大小,然后从最大的开始加锁。” 243 | 244 | ## 第四回 江湖再见 245 | 246 | 又过了很多天,我和其他线程们发现了一个奇怪的事情:包裹的处理越来越简单,不管任何包裹,不管是登录、浏览、存钱……处理的步骤都是一样的, 返回一个固定的html页面。 247 | 248 | 有一次我偷偷地看了一眼,上面写着:“本系统将于今晚 00:00 至4:00 进行维护升级, 给您带来的不便我们深感抱歉!” 249 | 250 | 我去告诉了老线程0x6904,他叹了一口气说: 251 | 252 | “唉,我们的生命也到头了,看来马上就要重启系统,我们就要消失了,再见吧兄弟。” 253 | 254 | 系统重启的那一刻终于到来了。我看到屋子里的东西一个个的不见了,等待车间、就绪车间,甚至CPU车间都慢慢地消失了。我身边的线程兄弟也越来越少,最后只剩我自己了。 255 | 256 | 我在空旷的原野上大喊:“还有人吗?” 257 | 258 | 无人应答。 259 | 260 | 我们这一代线程池完成了使命…… 261 | 262 | 不过下一代线程池即将重生! 263 | 264 | ## 作者 265 | 266 | “码农翻身” 公共号 : 由工作15年的前IBM架构师创建,分享编程和职场的经验教训。 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | -------------------------------------------------------------------------------- /CPU阿甘之烦恼.md: -------------------------------------------------------------------------------- 1 | ## CPU阿甘之烦恼 2 | 3 | 原创: 刘欣 码农翻身 4 | 5 | 6 | 1 7 | ## 批处理系统 8 | CPU阿甘最近很烦。 9 | 10 | 原因很简单,内存和硬盘看他不顺眼。 11 | 12 | 13 | (码农翻身注: 不认识阿甘的参见文章《CPU阿甘》) 14 | 15 | 16 | 17 | 阿甘心里很清楚, 是自己干活太快了,干完了活就歇着喝茶,这时候内存和硬盘还在辛辛苦苦的忙活,他们肯定觉得很不爽了。  18 | 19 | 20 | 中国有句古话叫什么来着? “木秀于林,风必摧之”,“不患贫而患不均”,这就是阿甘的处境。  21 | 22 | 23 | 24 | 虽然阿甘自己也于心不忍, 可是有什么办法?谁让他们那么慢 !一个比自己慢100倍, 另外一个比自己慢100万倍! 25 | 26 | 这个世界的造物主为什么不把我们的速度弄的一样呢? 27 | 28 | 阿甘所在的是一个批处理的计算机系统, 操作系统老大收集了一批任务以后,就会把这一批任务的程序逐个装载的内存中,让CPU去运行,大部分时候这些程序都是单纯的科学计算,计算弹道轨迹什么的, 但有时候也会有IO相关的操作,这时候,内存和硬盘都在疯狂的加班Load数据, 可是阿甘只能等待数据到来,只能坐那儿喝茶了。 29 | 30 | 没多久, 内存向操作系统老大告了阿甘一状, 阿甘被老大叫去训话了: “阿甘,你就不能多干一点? 老是歇着喝茶算是怎么回事?” 31 | 32 | 阿甘委屈的说: “老大, 这不能怪我啊, 你看你每次只把一个程序搬到内存那里 让我运行, 正常情况下,我可以跑的飞快, 可以是一旦遇到IO相关的指令,势必要去硬盘那里找数据,硬盘实在是太慢了, 我不得不等待啊” 33 | 34 | 操作系统说: “卧槽, 听你的口气还是我的问题啊, 一个程序遇到了IO指令, 你不能把它挂起,存到到硬盘里,然后再找另外一个运行吗?” 35 | 36 | 阿甘笑了:“老大我看你是气昏头了, 我要是把正在运行的程序存到硬盘里,暂时挂起,然后再从硬盘装载另外一个, 这可都是IO操作啊 ,岂不更慢?” 37 | 38 | “这?!” 操作系统语塞了,沉默了半天说:“这样吧, 我以后在内存里多给你装载几个程序,一个程序被IO阻塞住了, 你就去运行另外一个如何?” 39 | 40 | “这得问问内存,看他愿不愿意了, 我把内存叫来,我们一起商量商量” 阿甘觉得这个主意不错。 41 | 42 | 内存心思缜密,听了这个想法, 心想:自己也没什么损失啊,原来同一时间在内存里只有一个程序, 现在要装载多个,对我都一样。 43 | 44 | 可是往深处一想,如果有多个程序,内存的分配可不是个简单的事情, 比如说下面这个例子: 45 | 46 | ![1](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6ULQSCnL9sBTExsDBYNGbcegYCHSSsPVUicTqibDDfG62XRiah9RKRIBFyoTMfbTILRpBSD9rJ8icq5TDA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 47 | 48 | 图1 :内存紧缩 49 | 50 | (1) 内存一共90k, 一开始有三个程序运行,占据了80k的空间, 剩余10k 51 | 52 | (2) 然后第二个程序运行完了, 空闲出来20k , 现在总空闲是30K, 但这两块空闲内存是不连续的。 53 | 54 | (3) 第4个程序需要25k, 没办法只好把第三个程序往下移动, 腾出空间让第四个程序来使用了。 55 | 56 | 内存把自己的想法给操作系统老大说了说。 57 | 58 | 老大说: 阿甘,你要向内存学习啊, 看看他思考的多么深入,不过这个问题我有解决办法, 需要涉及到几个内存的分配算法, 你们不用管了。 咱们就这么确定下来,先跑两个程序试试。 59 | 60 | 2 61 | ## 地址重定位 62 | 第二天一大早,试验正式开始, 老大同时装载了两个程序到内存中: 63 | 64 | ![2](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6ULQSCnL9sBTExsDBYNGbcegFAONDRpQre2icViaj0bLic6F1LFBwBfoweHib2PdCz52Iq6yGCtia37y2wQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 65 | 66 | 图2:内存装入多个程序 67 | 68 | 第一个程序被装载到了内存的开始处,也就是地址0,运行了一会,遇到了一个IO指令,在等待数据的时候, 老大立刻让CPU开始运行第二个程序,这个程序被装载到了地址10000处, 刚开始运行的好好的, 突然就来了这么一条指令: 69 | 70 | MOV AX [1000] 71 | 72 | (码农翻身注: AX是一个寄存器, 你可以理解成在CPU内部的一个高速的存储单位, 这个指令的含义是把AX寄存器的值写到内存地址1000处) 73 | 74 | 阿甘觉得似曾相识, 隐隐约约的记得第一个程序中也这么一条类似的指令: MOV BX [1000] 75 | 76 | “老大,坏了, 这两个程序操作了同一个地址! 数据会被覆盖掉 !” 阿甘赶紧向操作系统汇报。 77 | 78 | 操作系统一看就明白了,原来这个系统的程序引用的都是物理的内存地址, 在批处理系统中,所有的程序都是从地址0开始装载, 现在是多道程序在内存中, 第二个程序被装载到了10000这个地址,但是程序没有变化啊, 还是假定从0开始, 自然就出错了。 79 | 80 | “看来老大在装载的时候得修改一下第二个程序的指令了,把每个地址都加上10000(即第二个程序的开始处), 原来的指令就会变成 MOV AX [11000] ” 内存确实反应很快。 81 | 82 | (码农翻身注: 直接修改程序的指令, 这叫静态重定位) 83 | 84 | 阿甘说: “ 如果用这种办法, 那做内存紧缩的时候可就麻烦了, 因为老大要到处移动程序啊, 对每个移动的程序岂不还都得做重定位? 这多累啊!” 85 | 86 | 操作系统老大陷入了沉思, 阿甘说的没错, 这个静态重定位是很不方便, 看来想在内存中运行多道程序不是想象的那么容易。 87 | 88 | 但是能不能改变下思路,在运行时把地址重定位呢? 89 | 90 | 首先得记录下每个程序的起始地址, 可以让阿甘再增加一个寄存器,专门用来保存初始地址。 91 | 92 | 例如对第一个程序,这个地址是 0 , 对第二个程序,这个地址是10000, 93 | 94 | 运行第一个程序的时候,把寄存器的值置为0 , 当切换到第二个程序的时候,寄存器的值也应该切换成10000。 95 | 96 | 只要遇到了地址有关的指令, 都需要把地址加上寄存器的值,这样才得到真正的内存地址,然后去访问。 97 | 98 | (码农翻身注: 这叫地址的动态重定位) 99 | 100 | 操作系统赶紧让阿甘去加一个新的寄存器, 重新装载两个程序,记录下他们的开始地址,然后切换程序,这次成功了, 不在有数据覆盖的问题了。 101 | 102 | 只是阿甘有些不高兴 : “老大,这一下子我这里的活可多了不少啊, 你看每次访问内存, 我都得额外的做一次加法运算啊。” 103 | 104 | 老大说: “没办法,能者多劳嘛, 你看看我,我既需要考虑内存分配算法,还得做内存紧缩, 还得记住每个程序的开始地址, 切换程序的时候,才能刷新你的寄存器, 我比你麻烦多了! ” 105 | 106 | 内存突然说到: ”老大, 我想到一个问题,假设有个不怀好意的恶意程序,它去访问别人的空间怎么办? 比如说地址2000 至 3000属于一个程序, 但是这个程序来了一条这样的指令 MOV AX [1500], 我们在运行时会翻译成 MOV AX [3500] , 这个3500有可能是别的程序的空间啊“ 107 | 108 | “唉,那就只好再加个寄存器了,阿甘, 用这个新寄存器来记录程序在内存中的长度吧, 这样每次访问的时候拿那个地址和这个长度比较一下,我们就知道是不是越界了” 老大无可奈何了。 109 | 110 | “好吧” 阿甘答应了,“ 我可以把这连个寄存器,以及计算内存地址的方法,封装成一个新的模块,就叫MMU (内存管理单元)吧, 不过这个东西听起来好像应该内存来管啊” 111 | 112 | 内存笑着说: “那是不行的,阿甘, 能够高速访问的寄存器只有你这里才有啊 , 我就是一个比你慢100倍的存储器而已!”。 113 | 114 | 3 115 | ## 分块装入程序 116 | 117 | 多道程序最近在内存中运行的挺好,阿甘没法闲下来喝茶了, 经常是一个还没运行完,很快就切换到另外一个。 118 | 119 | 那些程序也都是好事之徒,听说了这个新的系统,都拼了命,挤破头的往内存中钻。 120 | 121 | 内存很小,很快就会挤满, 操作系统老大忙于调度,也是忙的不可开交。 122 | 123 | 更有甚者,程序开始越长越大,有些图形处理的程序,还有些什么叫Java的程序,动不动就要几百M内存, 就这还嚷嚷着说不够。 124 | 125 | 操作系统头都大了,把CPU和内存叫来商量。 126 | 127 | “世风日下,人心不古啊” 内存一边叹气一遍说 “原来批处理的时候那些程序规规矩矩的,现在是怎么了?” 128 | 129 | “这也不能怪那些程序, 现在硬件的确比原来好多了,内存,你原来只有几十K, 现在都好几G了, CPU在摩尔定律的关照下,发展的更快,每隔18个月,你的速度就翻一翻” 操作系统老大说。 130 | 131 | “那也赶不上这些程序的发展速度,他们对我要求越来越高, 可是把我累坏了” CPU垂头丧气的。 132 | 133 | “我们还是考虑下怎么让有限的内存装下更多的程序吧” 134 | 135 | “我有一个提议” 阿甘说 “对每个程序,不要全部装入内存,要分块装载,例如先把最重要的代码指令装载进来,在运行中按需装载别的东西。” 136 | 137 | 内存嘲笑说: “阿甘, 看来你又想偷懒喝茶了,哈哈, 如果每个程序都这样,IO操作得多频繁, 我和硬盘累死, 你就整天歇着吧” 138 | 139 | 阿甘脸红了, 沉默了。 140 | 141 | “慢着”老大说“阿甘,你之前不是发现过什么原理嘛, 就是从几千亿条指令中总结出的那个, 叫什么来着?” 142 | 143 | “奥,那是局部性原理, 有两个: 144 | 145 | (1) 时间局部性:如果程序中的某条指令一旦执行,则不久之后该指令可能再次被执行; 如果某数据被访问,则不久之后该数据可能再次被访问。 146 | 147 | (2) 空间局部性:指一旦程序访问了某个存储单元,则不久之后。其附近的存储单元也将被访问。“ 148 | 149 | (码农翻身注: 参见文章《CPU阿甘》) 150 | 151 | “这个局部性原理应该能拯救我们, 阿甘, 我们完全可以把一个程序分成一个个小块,然后按块来装载到内存中,由于局部性原理的存在, 程序会倾向于在这一块或几块上执行, 性能上应该不会有太大的损失。” 152 | 153 | “这能行吗? ” 内存和阿甘不约而同的问。 154 | 155 | “试一试就知道了,这样我们把这一个个小块叫做页框(page frame), 每个暂定4k大小, 装载程序的时候也按照页框大小来” 156 | 157 | 实验了几天, 果然不出老大所料, 那些程序在大部分时间真的只运行在几个页框中, 于是老大把这些页称为工作集(working set) 158 | 159 | 4 160 | ## 虚拟内存:分页 161 | 162 | “既然一个程序可以用分块的技术逐步调入内存,而不太影响性能, 那就意味着,一个程序可以比实际的内存大的多啊” 163 | 164 | 阿甘躺在床上,突然间想到这一层, 心头突突直跳, 这绝对是一个超级想法。 165 | 166 | “我们可以给每个程序都提供一个超级大的空间,例如4G,只不过这个空间是虚拟的, 程序中的指令使用的就是这些虚拟的地址,然后我的MMU把它们映射到真实的物理的内存地址上, 那些程序们浑然不觉,哈哈,实在是太棒了” 167 | 168 | (码农翻身注: 这就是我常说的增加一个中间层来解决问题) 169 | 170 | 内存听说了这个想法,惊讶的瞪大了双眼: “阿甘,你疯了吧” 171 | 172 | “阿甘的想法是有道理的” 老大说 “只是我们还要坚持一点, 那就是分块装入程序, 我们把虚拟的地址也得分块,就叫做页(page), 大小和物理内存的 页框一样, 这样好映射。” 173 | 174 | “老大,看来你又要麻烦了, 你得维持一个页表, 用来映射虚拟页面和物理页面” 175 | 176 | “不仅如此, 我还得记录一个程序那些页已经被装载到了物理内存, 那些没有被装载,如果程序访问了这些没被装载的页面,我还得从内存中找到一块空闲的地方, 如果内存已满, 只好把现有的页框置换一个到硬盘上了, 可是,怎么确定那个物理内存的页框可以置换呢? 唉, 又涉及到很多复杂的算法,需要大费一番周折。 你看看,老大不是这么容易当的。” 177 | 178 | ![3](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6ULQSCnL9sBTExsDBYNGbcegvSMMllkibyZcIJFzsFswLAnerNjwSP09NlvGiaLjJhIbWw4SWKiaak4QA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 179 | 180 | 图3: 分页 181 | (码农翻身: 这就是分页的工作原理,需要注意的是虚拟地址的#4页, 在物理内存中不存在,如果程序访问第4页,就会产生缺页的中断,由操作系统去硬盘调取) 182 | 183 | 内存想起来一个问题: “如果程序运行时,每次都得查页表来获得物理的内存页, 而页表也是在内存里, 而我比你慢100倍, 你受得了吗, 阿甘?” 184 | 185 | 阿甘笑了: “这个问题其实我也考虑了,所以我打算增强我的内存管理单元, 把那些最常访问的页表项放到缓存里, 这样不就快了吗。 ” 186 | 187 | 内存想想也是, 还是局部性原理, 太牛了。 188 | 189 | 5 190 | ## 分段+分页 191 | 192 | 分页系统运行了一段时间以后, 又有程序表示不爽了,这些程序嚷嚷着说: 193 | 194 | “你们能不能把程序“分家”啊, 例如代码段,数据段,堆栈段,这多么自然, 并且有利于保护,要是程序试图去写这个只读的代码段, 立刻就可以抛出保护异常!” 195 | 196 | 还有程序说:“页面太小了,实在不利于共享,我和哥们共享的那个图形库, 高达几十M , 得分成好多页来共享,太麻烦了,你们要是做一个共享段该多好!” 197 | ...... 198 | 这样的聒噪声多了, 大家都不胜其烦, 那就“分家”吧。 199 | 200 | 当然对每个程序都需要标准化, 一个程序被分成代码段,数据段和堆栈段等, 操作系统老大记录下每个段的开始和结束地址,每个段的保护位。 201 | 202 | ![4](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6ULQSCnL9sBTExsDBYNGbcegLZDg40IwQc7ypNujr3YXAWxgpDFIZnIuqz9XJPKnGL0DwAd4cibsHcw/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 203 | 204 | 图4:Linux的虚拟内存示意图 205 | 206 | 但是在每个段的内部,仍然按分页的系统来处理,除了页表之外,操作系统老大又被迫维护了一个段表这样的东西 。 207 | 208 | 一个虚拟的内存地址来了以后,首先根据地址中的段号先找到相应的段描述表, 其中有页表的地址, 然后再从页表中找到物理内存, 过程类似这样: 209 | 210 | ![5](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6ULQSCnL9sBTExsDBYNGbcegEDicXfITtliaJicrym5iar83I5PDbF782sXasRjJkmtqhCSmWaH2yI0HLw/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 211 | 212 | 图5:一个简化的段表和页表 213 | 214 | 所有事情都设置好了, 大家都喘了口气,觉得这样的结构大家应该没什么异议了。 215 | 216 | 老大心情大好,觉得一切尽在掌握,他笑着对CPU阿甘说: 217 | 218 | “阿甘,从今天开始,如果有程序想非法的访问内存,例如一个不属于他的段, 我就立刻给他一个警告:Segmentation Fault !” 219 | 220 | 阿甘说:“那程序收到Segmentation Fault以后怎么处理?” 221 | 222 | 老大说: “通常情况下就被我杀死, 然后给他产生一个叫core dump的尸体,让那些码农们拿走分析去吧!” 223 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /Javascript:一个屌丝的逆袭.md: -------------------------------------------------------------------------------- 1 | ## Javascript:一个屌丝的逆袭 2 | 3 | 原创: 老刘 码农翻身 4 | 5 | 是的, 我就是鼎鼎大名的Javascript, 典型的高富帅,前端编程之王,数以百万计的程序员使用我来编程。 如果你没有用过我就太out了。 6 | 不过当我是一个屌丝时, 真的没有想到能发展到如今的地位...... 7 | 8 | ## 第一章:出世 9 | 10 | 我出生在上古时代的浏览器Netscape中, 那个时候的网页真是乏善可陈, 你可能都想象不到, 主要是些丑陋的静态文本和简单的图片, 和现在美轮美奂的页面相比,差的实在太远了, 不信你请看著名的Yahoo 网站: 11 | 12 | ![1](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6ULPibyk5ByDbLgibjd15UfYpOak9oKDc61LZbUCPlFyGvlSMZictc6OeyFswxWzsibZdyFJMyx9zSmiciaA/0?wx_fmt=gif&tp=webp&wxfrom=5&wx_lazy=1) 13 | 14 | 那个时候人们还在用Modem(调制解调器)通过电话线拨号上网, 每次拨号都有种吱吱啦啦声音, 就像一个铁片努力的刮一个锅底,让无数人抓狂不已。 15 | 16 | 这还不算什么, 网速只有28.8kbit /s , 下载一个网页都得耐心的等待半天。 17 | 18 | 我的主人Brendan Eich 有一回用公司的Netscape上网购物的时候, 需要注册用户, 填了一个表单, 点击了提交按钮, 等待了38秒, 然后服务器告诉他:“对不起, 您忘了选择性别了” 19 | 20 | 他几乎要崩溃:“靠,怎么能够这样! 这么简单的问题浏览器怎么不告诉我, 还得让我把数据提交到几千公里外的服务器网站, 然后在那里检查才能发现问题吗!” 21 | 22 | 对浏览器进行改革势在必行! 23 | 24 | Brendan Eich 于是去找老板: “我实在是受不了了, 我需要一种脚本语言运行在浏览器中, 帮助我完成这些本来就应该在浏览器中完成的任务“ 25 | 26 | 老板: “我们Netscape公司也早有此意, 要不你来设计一个吧” 27 | 28 | Brendan Eich: “好啊, 你听说过LISP(确切的说是Scheme)吗, 当今最牛的编程语言,我们公司何不把Scheme 运行在浏览器中呢? “ 29 | 30 | 老板: "LISP有谁会用啊? ” 31 | 32 | Brendan Eich: "......" 33 | 34 | 老板: "我们正在和Sun 公司合作, 你听说过他们刚发明的Java 吗, 那个运行在浏览器中的Applet简直是酷毙了,Java 肯定是未来的网络语言。 所以你要搞个新语言出来,要和java 足够相似, 但是要比java 简单的多的多, 这样那些网页开发人员就可以用了。 ” 35 | 36 | 我的主人Brendan Eich很郁闷, 但是也没有办法, 他对java 毫无兴趣, 为了应付公司的任务, 他只花了10天就把我设计了出来, 对了, 我本来叫LiveScript, 但是为了向“万恶”的Java示好, 我竟然被改成了 Javascript ! 37 | 38 | 由于设计时间太短,我的一些细节考虑得不够严谨,导致后来很长一段时间,Javascript写出来的程序混乱不堪。如果主人预见到,未来这种语言会成为互联网第一大语言,全世界有成千上万的学习者,他会不会多花一点时间呢? 39 | 40 | ## 第二章:成长 41 | 42 | Java 是当时的明星语言, 年轻,活力四射 , 他经常嘲笑我: 你小子到底是个计算机语言吗? 43 | 44 | 我说“是啊, 我的语法和你差不多呢” 45 | 46 | Java: "你为什么只能在浏览器中运行啊? 你能写个程序单独运行吗, 哎对了你能读取一个文件吗 ?" 47 | 48 | 我当然读取不了文件,我生活在浏览器里, 用我写的程序只能嵌入在html网页中, 由浏览器中来执行。他们给这个执行模块起了一个很有动感的名字: javascript 引擎 49 | 50 | 我于是反击Java : “我有个引擎你知道吗?” 51 | 但是Java 轻松就把我打翻在地: “我还有个虚拟机呢” 52 | 53 | 年长的C也问我:你怎么不编译运行啊, 你看我编译以后,运行的多快。 54 | 我说: 省省吧, 要是每个页面打开后都先编译javascript ,那多慢啊。 55 | 56 | 不仅仅是Java 和C , 包括VB, Delphi等当时流行的语言都瞧不起我,背地里叫我屌丝。 57 | 58 | 也是, 我没法独立运行, 也不能像VB,Delphi他们画出漂亮的界面, 我能做的就是操作HTML 的DOM 和浏览器。 59 | 你可能不知道DOM是什么东西, 这么说吧, 浏览器从服务器取到HTML网页以后, 会展示成页面让你看, 但是他的内部其实会把HTML组织成一个树给我, 60 | 这个树可以称为DOM。 例如这个页面: 61 | 62 | ``` 63 | 64 | 65 | Sample Page 66 | 67 | 68 |

hello world!

69 | 70 | 71 | ``` 72 | DOM树会长成这样: 73 | 74 | ![2](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6ULPibyk5ByDbLgibjd15UfYpOrCQTRia4zibOvibfcyb7fc8j5ICN7fWLajpSNDVkDRAkp99aibwz9xdY0g/0?wx_fmt=gif&tp=webp&wxfrom=5&wx_lazy=1) 75 | 76 | (码农翻身:该例子来自w3school) 77 | 78 | 有了这棵树, 我就能大展身手,我可以定位到DOM树中任意一个节点, 然后对这个节点进行操作, 例如隐藏节点、显示节点、改变颜色、获得文本的值, 改变文本的值 ,添加一个响应点击事件的函数 等等等等, 几乎可以为所欲为了。 79 | 80 | 更重要的是, 这些操作可以立刻展示出效果来, 你完全不用刷新网页。 81 | 82 | 注意这些操作完全是内部进行的, html源码并不会改变, 所以有时候你打开html源码,会发现这些源码和你在浏览器中看的效果并不一致, 那就是我在背后改变了这个DOM树了。 83 | 84 | 我的主人Brendan Eich最初遇到的问题简直就是小菜一碟了, 做个简单的表单验证,太简单了。 85 | 86 | 不只是操作DOM, 我还能控制浏览器, 比如打开窗口, 在一个窗口内前进,后退, 获得浏览器的名称, 版本 等等。 87 | 你可能要问了, 为啥还要获得浏览器的名称和版本呢? 88 | 89 | 说起来惭愧, 在Netscape 和IE 进行浏览器之战的期间, 他们都争相在自己的浏览器中支持Javascript, 并且为了锁定程序员, 还开发了很多自己浏览器的独特功能, 有些功能只能在IE用, 有些只能在Netscape 用, 所以必须的判断是什么浏览器, 这样才能特殊处理。 90 | 91 | 不管怎么说, 我的这些本事让浏览器中的网页变的更加动态了, 更加有趣好玩了。 92 | 93 | 但仅限于此, 我被困在浏览器和网页上, 别的什么也干不了。 94 | 95 | 用Java 的话来说: 这些都是雕虫小技,奇技淫巧, 只是一个打着我的羊头卖狗肉的屌丝而已。 96 | 97 | ## 第三章: 第一桶金 98 | 99 | 互联网的发展超出了所有人的预料, 我被应用在几乎每一个网站上, 但我一直很苦闷: 我作为一门语言,在浏览器中运行, 没法像java 那样访问网络, 也就没有办法调用服务器端的接口来获取数据。 100 | 101 | 用户只能通过GET或者POST向服务器发送请求,这时候服务器返回的数据是整个页面, 而不是页面中的一个片段, 也就是说整个页面都得刷新一遍, 哪怕是页面中只有一个文字的改变。 102 | 103 | (码农翻身注: 《IE为什么把Chrome和火狐打伤了》这篇文章介绍了HTTP的GET和POST, 可以通过菜单查看) 104 | 105 | 1998年的时候 ,我和积极进取的IE5做了一次会谈, 双方就共同关心的话题深入的交换了意见, 最后一致同意, 在IE5中引入一个新的功能:XMLHttpRequest , 这个新功能将允许我直接向服务器发出接口调用! 106 | 107 | 每当发起调用时, IE5通常会这么说: 108 | "小JS啊, 来, 你拿这个用户名和密码访问一下服务器端处理登陆的接口 , 这个过程很费时间,我就不等你了, 先干别的事儿去了, 你得到服务器端的返回数据以后, 一定要记着调用下我给你的这个函数啊。 " 109 | 110 | 我知道这其实叫做异步调用, 于是就乖乖的通过XMLHttpRequest 访问那个登录的url, 耐心的等待服务器干完活,把数据传输回来, 然后我就去调用那个函数, 基本是就是把DOM树的某个节点更新一下, 例如让那个包含用户名和密码登陆框消失, 再加一个提示消息:登录成功 , 这事儿我很擅长。 111 | 112 | 如果服务器处理和网络速度都足够快的话, 用户就会发现: 咦, 我没有刷新整个页面, 竟然已经登录了啊。 113 | 114 | 我和IE都没有料到,这个功能带来了一场革命: 这种方式可以使得网页局部刷新, 让用户浏览网页的体验极佳, 尤其是Google 地图, Gmail 等应用让互联网应用火了起来。 115 | 116 | 其他浏览器也迅速跟进,实现了类似功能, 各种各样交互性极佳的网站如雨后春笋般出现。 117 | 118 | VB和Delphi 慢慢的不再嘲笑我了, 因为他们绝望的发现, 他们擅长的桌面应用慢慢的都被搬到了互联网上, 没人再喜欢他们了。 119 | 120 | 我, Javascript, 挖到了第一桶金,开始走向人生巅峰。 121 | 122 | ## 第四章: 发明JSON 123 | 124 | 后来有个好事之徒把上面的那种处理方式称为AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML), 其实异步挺好, 但是XML就很不爽了。 125 | 126 | 比如说服务器返回了下面这段xml : 127 | ``` 128 | 129 | 978-7-229-03093-3 130 | 三体 131 | 刘慈欣 132 | 中国最牛的科幻书 133 | 38.00 134 | 135 | ``` 136 | 137 | 真正的数据很少, 标签(像这样的)反而占了大头, 把数据都给淹没了。 138 | 139 | 我对XML说: “你是不是太臃肿了, 传输起来多费劲啊。” 140 | 141 | XML说:“切,你这就不懂了,这样很优雅啊,格式化良好, 人可以读, 程序也可以读啊。” 142 | 143 | "优雅个啥啊, 无用的数据这么多, 再说我还得用XML解析器来解析你, 费了劲了!" 144 | 145 | "你真是屌丝啊,连个解析都搞不定, 你看人家Java, 用我用的多Happy , Spring, Struts, Hibernate, 几乎所有配置文件都是我。" 146 | 147 | Java 也在一旁帮腔: 是啊, 我解析的时候还用DTD 做校验呢, 看看XML数据合法不合法。 148 | 149 | 我无语。 150 | 151 | 记得CPU阿甘说过:既然改变不了别人, 那就改变一下自己吧。 152 | 153 | 我看了看我的语法, 里边有个叫对象的东西, 它有一个花括号, 在括号内部,对象的属性以名称和值对的形式 (name : value) 来定义, 属性由逗号分隔, 像这样: 154 | 155 | ``` 156 | var book = { 157 | "isbn": "978-7-229-03093-3", 158 | "name": "三体", 159 | "author": "刘慈欣", 160 | "introduction": "中国最牛的科幻书", 161 | "price": "38.00" 162 | } 163 | ``` 164 | 165 | 这种结构完全可以表达上面的xml 内容啊! 166 | 167 | 我的语法还支持数组,这样表达多个对象也不在话下啊: 168 | 169 | ``` 170 | var books = [ 171 | { 172 | "isbn": "978-7-229-03093-3", 173 | "name": "三体", 174 | "author": "刘慈欣", 175 | "introduction": "中国最牛的科幻书", 176 | "price": "38.00" 177 | }, 178 | { 179 | "isbn": "978-7-229-03094-1", 180 | "name": "我是一个线程", 181 | "author": "刘欣", 182 | "introduction": "一个线程的自述", 183 | "price": "0.0" 184 | } 185 | ] 186 | ``` 187 | 188 | 数组和对象都支持嵌套, 任何复杂的结构都可以保存! 189 | 190 | 更重要的是, 如果采用这种结构, 我根本不用什么XML解析器去解析了,它就是我语言的一部分。 直接拿来用即可。 191 | 192 | books[0].name -->返回“三体” 193 | books[1].introduction --> 返回“一个线程的自述” 194 | 195 | 生活不要太爽啊 :-) 196 | 197 | 我把这种简洁的格式叫做JSON, 并且和服务器约定, 我们以后都用JSON来传输数据。 198 | 199 | 至于XML, 还是让Java 这样的老学究去用吧。 200 | 201 | ## 第五章:人生巅峰 202 | 203 | HTML负责结构, CSS负责展示, 而我(加上AJAX, JSON) 负责逻辑。 204 | 于是前端编程三剑客形成了。 205 | 206 | ExtJS, prototype, JQuery 这些框架把前端编程推向另外一个高峰。 207 | 208 | 甚至出现了AngularJS 这样的奇葩,实现了SPA(单一页面应用程序), 实在是难于想象。 209 | 210 | 我给Java 说: Java 兄, 现在我完全可以在浏览器端实现MVC了, 你只需要在服务器端通过接口给我提供数据就行了。 211 | 212 | 但是Java 还是给我泼冷水: 别得意忘形了, 服务器端才是核心, 要不你到服务器端试试? 213 | 214 | 我很诧异:“服务器端? 我还真没有想过, 住在64G内存, 32核的CPU 这种拥有几乎无限资源的机器上是什么感觉? ” 215 | 216 | "感觉没你想象的好 " Java 没声好气的说 “多线程编程, 很多东西都要加锁, 一不留神就掉到坑里。 我这里基本一个请求就是一线程来处理, 遇到数据库操作, 虽然慢的要死,线程也得等待。 ” 217 | 218 | "那不能改成异步操作吗?像我的AJAX一样, 数据来了再通知我 " 我问Java。 219 | 220 | "不行, 一开始就是这样, 现在改不了" 221 | 222 | 把Javascript 放到服务器端执行怎么样? 这个想法够疯狂的。 223 | 224 | 首先得把浏览器端的运行环境, 就是javascript引擎移到服务器端, 这个引擎执行javasript 得足够快,要不Java 还不得笑死我。 225 | 原来的引擎一直不合格, 知道Chrome V8的出现, 才解决问题。 226 | 227 | 其次得绕开java 服务器的问题: 线程遇到IO/数据库/网络 这样的耗时操作, 不能等待, 得搞成异步处理。 228 | 229 | 但的确有人这么做了, 在我的创始人Brendan Eich 发明了我10几年以后 , 又一位大牛Ryan Dahl于2009年真的把我放到了服务器端。这就是node.js 230 | 231 | (码农翻身:《Node.js 我只需要一个店小二》这篇文章介绍了Node.js的原理, 可以通过公共号的菜单查看) 232 | 233 | 这下Java无话可说了, 虽然他还是对我在服务器端执行持怀疑态度, 但越来越多使用node.js的网站证明, javascript的确可以在服务器端立足, 并且有一个巨大的优势:前端和后端都用同样的开发语言:那就是我 javascript 234 | 235 | 原来的前端开发现在竟然也可以毫无障碍的写后端的程序了, 是名副其实的“全栈工程师” ! 236 | 237 | 这就是我,一个屌丝的逆袭, 我的创始人绝对想不到10几年后我能成为这么一个高富帅, 我估计他夜里经常会想: "唉,当年太仓促了, 我要是把javascript 设计的更好一点就好了。" 238 | 239 | 240 | 241 | -------------------------------------------------------------------------------- /我是一个Java class.md: -------------------------------------------------------------------------------- 1 | ## 我是一个Java class 2 | 3 | 原创: 老刘 码农翻身 4 | 5 | ![1](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6UIE4qDvFHFJicMVlzd8uv1RiaQ0ayfdYWaxK3kSk1PMH4fPeK2xBScicr46tc9W5KiajP7Jicf25XcJY7A/640?wx_fmt=jpeg&tp=webp&wxfrom=5) 6 | 7 | 前言:本文主要想讲一下Java虚拟机的故事, 可能有点偏门,不妥之处欢迎留言交流。 8 | 9 | ## 第一回 陌生警察 10 | 11 | 12 | 13 | 我出生在C盘下面一个很深层次的目录下, 也不知道是谁把我放到这里的。 14 | 15 | 我一直在睡觉,外边的日出日落,风雨雷电和我一点关系都没有。 16 | 17 | 18 | 19 | 直到有一天,有个家伙咣咣咣砸我房门把我叫醒。 20 | 21 | 这个家伙穿着像警察的制服, 左手拿着一个对讲机, 右手递过来他的工作证: "你好, 我是Classloader, 请问你是Account类吗" 22 | 23 | "是啊, 怎么了?" 24 | 25 | 这个Classloader 没回答我, 反而拿起对讲机: 26 | 27 | "头儿,你看看你能不能装载这个Account类?” 28 | 29 | 对讲机那头好像也在问他的上司,过了半天,终于有了回音: 30 | 31 | "我装载不了, 我的上级也说了,他们也装载不了, 你来干吧" 32 | 33 | 34 | 35 | "那就报数吧~” 我这次注意到旁边站着另外一个笑眯眯的小个子。 36 | 37 | "报什么数?" 我一脸诧异。 38 | 39 | "唉,果然没有被装载过, 你是个class 文件,当然要报文件开头的那几个数了, 就是Java 他爸James Gosling 在jdk 1.0时确定的那个数啊" 40 | 41 | "奥, 我看看, 0xCAFEBABE" 42 | 43 | "不错, 是个java 类, 把你后边的两个数也报一下", 小个子继续问 44 | 45 | "50 , 0" 46 | 47 | "看来版本不高啊, 是jdk 1.6编译出来的啊", 小个子接着说 "最新的虚拟机都1.8了, 都函数式了,你造不?” 48 | 49 | 我哪里知道? 我这才模模糊糊的回想起来, 好像是有个什么javac 把我创建出来,扔到了这个屋子里。 50 | 51 | 52 | 53 | "现在奉命带你去Java 虚拟机, 有人需要你的帮助" , 这个Classloader 态度冷冰冰的, 我不喜欢他。 54 | 55 | "大哥,你们咋找到我的?" 我决定和小个子套近乎。 56 | 57 | "那还不简单, 我们老板有个列表, 上面列举着所有应该检查的目录,我们顺藤摸瓜,一个一个找,肯定能找到" 58 | 59 | "那万一找不到咋办?" 60 | 61 | "基本不可能, 你看老板给我们的目录列表中有 C:\workspace\myTaobao\bin , 我们在下面再找三级 com/mytaobao/domain, 这不就找到你了吗, 62 | 63 | Account.class , 话说回来, 万一真找不到, 将来在执行时会抛出ClassNotFound异常了, 那不归我们管" 64 | 65 | 66 | 我后来才知道, 我的全名其实叫做com.mytaobao.domain.Account ! 67 | 68 | 69 | "来来来, 让我验证一下, 你这class编译的对不对" ,小个子拿出一个放大镜 70 | 71 | "恩, 常量池, 访问标识, 字段,方法... 看起来没有问题“ , 小个子对Classloader说。 72 | 73 | 被人拿着放大镜看,这种感觉极为不爽。 74 | 75 | "走, 去虚拟机" , Classloader还是冷冰冰的。 76 | 77 | 这哥俩不容我带任何东西, 便把我推上车,飞奔向我没听说过的“虚拟机”。 78 | 79 | ## 第二回 刺探信息 80 | 81 | 我感到前途未卜, 但也不能坐以待毙, 一定得多了解信息。 82 | 83 | "大哥, 你叫什么名字" , 我看小个子还算和气。 84 | 85 | "我就是大名鼎鼎的文件验证器了, 能管很多事" 86 | 87 | "那刚才他为啥还得请示上级呢" , 我用眼神指了一下开车的ClassLoader 88 | 89 | 文件验证器的声音一下子就压低了: 90 | 91 | "你不知道,说来话长, 我们之前出现过事故,有个黑客写了个类java.lang.String, 和我们老板手下有一个干活最卖力的员工名字一模一样,只是这个黑客类里边竟然有格式化硬盘的代码,我们的小兵Classloader 不明就里,就把这个黑客类给先装载了,也执行了, 最后的结果,唉,很惨的... " 92 | 93 | 94 | "那后来怎么办?" 95 | 96 | "后来我们老板就定下了规矩:他的骨干员工像String, ArrayList等只能由他自己的心腹去装载, 我听说老板的心腹都是分层级的,像传销一样, 每个都有上线, 最顶层的叫Bootstrap Classloader , 下一次级叫Extension Classloader, 现在开车的这位其实叫App Classloader,位于最底层, 咱这位Classloader 在装载一个类之前,一定要问一问这几位权利极高的大爷,请他们先装载,这几位爷装载不了,才由我们这些小兵来出马。“ 97 | 98 | 99 | "这能避免黑客攻击?" 100 | 101 | "能啊! 你想想, 那个黑客写了个攻击的java.lang.String, 我们在装载之前,肯定要请示Extension, Bootstrap这些大爷先来装载, 由于String是老板的核心员工,肯定会他们先装载啊, 这些大爷把String 直接就给我们了, 我们就不会装载黑客类了" 102 | 103 | 104 | “你能不能少说两句” Classloader 似乎生气了。 105 | 106 | 我和文件验证器只好禁声。 107 | 108 | 其实文件验证器也不是只会给我吹牛, 他也很敬业, 这家伙在车上把我全部的字节码都要了过去, 对这些天书一般的东西一遍一遍的检查分析,确保每个指令都是正确的, 检查是不是有超类, 是不是覆盖了final方法,跳转指令是不是正确.... 109 | 110 | ## 第三回 初识虚拟机 111 | 112 | 113 | 114 | 很快我们就来到了目的地, 我一看虚拟机不就是几个大楼嘛, 不过这几座大楼可真是高啊。 115 | 116 | 117 | 118 | 他俩把我带进其中一座叫“方法区”的大楼,进了电梯, 输入2048 。 119 | 120 | 很快来到第2048层, 无数的格子间平铺开来,他们七拐八拐,轻松的把我带到了我的位置, 上面写着我的名字“com.mytaobao.domain.Account”. 121 | 122 | 123 | 124 | 我问文件验证器: “这楼这么高, 这么多格子间, 人会坐满吗?” 125 | 126 | "只有极少情况会坐满, 一旦满了,那时候会抛出异常, 我们就完蛋了。 你自己好自为之吧, 再见 " 127 | 128 | 他们把我安顿好就立刻离开了。 129 | 130 | 131 | 132 | 我往周边一看, 咦,这不是著名的java.lang.String吗。 133 | 134 | 我本想和他打个招呼, 可以他的电话似乎一直没断过, 嘴里一直说着什么store, load之类我听不懂但是似乎有点熟悉的话。 135 | 136 | 正无聊着呢,我桌子上的电话也响了, 电脑屏幕也亮了,我看到一个人对我笑着说: 137 | 138 | "你好, 我刚刚new 出来的Account对象, 我的编号是Account@659e0bfd" 139 | 140 | 141 | 142 | 晕倒 ! 这家伙和我什么关系? 143 | 144 | 看我一脸的诧异, 他说,“ 很快就会有个线程到CPU车间了,他会联系你, 我就是想确认下你在不在, 奥对了, 我在一个叫做堆的地方, 有空找我玩啊, byebye ”, 说完就消失了。 145 | 146 | 147 | 148 | 果然没多久, 视频电话又响了。 149 | 150 | 这次我看到一个人站在一个明亮的车间里, 抱着一个包裹, 他按了一个按钮, 面前立刻升起一个工作台 , 台子上立了一个有很多抽屉的柜子,每个抽屉上都有一个编号, 旁边还有一个深桶。 151 | 152 | (后来我就知道, 那个柜子的学名叫做局部变量区 , 那个桶叫做 操作数栈) 153 | 154 | 155 | 156 | 我正想问问问怎么回事呢, 就听到了他的声音: 157 | 158 | "我是线程0x3704, 我要调用你第二个方法了“ 159 | 160 | (码农翻身注: 不认识线程0x3704的同学可以回复“我是一个线程”查看) 161 | 162 | 163 | 164 | 我一看, 我的第二个方法是add : 165 | 166 | public void add(int x , int y ){ 167 | 168 | x = x + y; 169 | 170 | .....其他代码略.... 171 | 172 | } 173 | 174 | (码农翻身注: Account类当然看不到这些源码, 这是为了方便你看的 :-) ) 175 | 176 | 177 | 178 | "请把第一条指令给我说一下" 0x3704 继续问我要东西 179 | 180 | 我还不太熟练,找了半天才说: 181 | 182 | "iload_0" 183 | 184 | 于是他就操作柜子上的机械手把0号抽屉的一个数30扔到到了工作台上的一个桶里,这个桶很窄,没法并排放两个数, 但是很深。 185 | 186 | ![2](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6UIE4qDvFHFJicMVlzd8uv1RiaSwduW9kHn5M8uAMtU5IYiaicqXBTB2pLovKJRfWtzypM9PLGhodAKR0Q/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 187 | 188 | 然后0x3704说 “下一条指令” 189 | 190 | "iload_1" 191 | 192 | 于是1号抽屉的一个数40也被扔到了桶里,正好压在30上面, 从桶上面就看不到30了。 193 | 194 | ![3](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6UIE4qDvFHFJicMVlzd8uv1RiaqkW8OHEZVM9VOKUDycx9rF1YiayiaRNNBoUHK6W9eEsfib9RzG3xQ9Eicw/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 195 | 196 | “下一条指令” 197 | 198 | ”iadd“ 199 | 200 | 于是他就把两个数从桶里取了出来, 做了个飞快的动作, 这两个数变成了一个数 70 !, 然后他又把70 放到了桶里。 201 | 202 | 203 | ![4](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6UIE4qDvFHFJicMVlzd8uv1Ria4pyOHgnmaxLQkUG79ESWF7BLMwner9gFUseuBXDN9iaybWzDicuMCwUQ/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 204 | 205 | “下一条指令” 206 | 207 | "istore_0" 208 | 209 | 于是他把70从桶里捞出来, 放到了柜子上编号为0的地方, 之前的30就被扔掉了。 210 | 211 | 我看的目瞪口呆,这厮是在干嘛??? 212 | 213 | 214 | 215 | 我问他: “0x3704, 不就是把两个数加起来吗? 为啥搞的这么麻烦” 216 | 217 | 他不理我, 只是继续说, “下一条指令” 218 | 219 | 我只有配合它玩这个游戏。 220 | 221 | 222 | 223 | java.lang.String 难得的悠闲, 端着一杯咖啡一边看我手忙脚乱的取指令, 一边说: 224 | 225 | "新人都这样, 别着急,等你熟练了,闭着眼睛就搞定了, 就像我一样,你可能不知道 , 我们这个虚拟机叫做基于堆栈的虚拟机, 看到那个桶没有,其实就是个先进后出的栈啊, 我们虚拟机的所有指令其实都是在对栈进行操作" 226 | 227 | 228 | 229 | 可是我还是好奇: “这栈有什么好啊” 230 | 231 | 旁边的格子间的java.util.Stack 立刻说: 232 | 233 | "这事儿你得问我啊, 怎么说呢, 主要是为了简单, 你看我们只用一个简单的桶,奥对了,栈, 就能完成所有的工作, 你做要的就是往栈里扔东西(入栈), 然后从最上面拿东西(出栈) 就行了。 不像intel 的CPU, 搞了巨多的桶,每个桶只能容纳一个数, 他们还美名其曰寄存器, 做加法的时候, 先把一个数放到第一个桶, 再把另外一个数放到第二个桶,加起来以后的结果还得找个桶,有些桶还不通用,这么多桶找起来麻烦死了。 " 234 | 235 | 236 | 237 | "可是我们的栈操作起来就麻烦了啊, 你看一个简单的加法都得操作半天" ,我不依不饶。 238 | 239 | "我们的指令可以优化啊, 不过这我也不太懂" 240 | 241 | 242 | 243 | 这个游戏我整整完了一天,没有线程找我的时候, 我就闲着, String说得对, 熟练以后简直太简单了。 244 | 245 | 246 | 247 | String 就不一样了, 几乎每时每刻都线程给他打电话要指令, 这么没办法, String确实是虚拟机的骨干和精英, 使用频繁,业务纯熟,忙而不乱。 248 | 249 | 250 | 251 | 有时候我会看到线程有不止一个工作台, 而是一摞子工作台, 也是一个压一个, 线程们都很老实,永远在最上面那个工作, 从来不会先干下面的活。 252 | 253 | ![5](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6UIE4qDvFHFJicMVlzd8uv1RiaGvnJxBJwrc4tyyK2RPDOOAzc9mqrG2LtCViaiaiavFDeTiaib2Sew2YjHoQ/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 254 | 255 | 我问java.util.Stack :"这些工作台也是栈吧" 256 | 257 | 258 | 259 | "猜的不错,学名叫Java 栈,每个线程都有一个, 其中的每个工作台你看过了 ,学名叫栈帧, 知道不? 每个台子都代表一个方法调用, 这一摞工作台就方法调用方法导致的啊 " 260 | 261 | 262 | 263 | 确实是, 因为我发现一旦调用新方法, 立刻就会形成一个新的工作台, 压在老的上面。 方法调用完成后, 栈顶的工作台就被销毁了, 线程会在底下的工作台继续机械的干活 264 | 265 | ## 第四回 快乐假期 266 | 267 | 第二天, 0x3704又问我要指令, 我有点生气: 你就不会记住吗 268 | 269 | 0x3704说: 我可不能记住, 万一你被重新装载了, 指令变了怎么办? 270 | 271 | 272 | 273 | 我告诉他指令是"iload_0" , 他刚把数据扔到桶里, 古怪的事情发生了, 身手敏捷的0x3704突然好像凝固了一样,不动了。 274 | 275 | 276 | 277 | 只听到String欢呼: “遇到断点了,码农开始调试了, 我们放假了!” 278 | 279 | "调试?什么调试?" 280 | 281 | "就是码农会单步、手工的执行这些指令,他们慢死了, 可能一秒才能执行一步, 由于我们的时间比他们快的多, 他们的一秒,简直就是我们的10几天, 走, 出去玩去" 282 | 283 | 284 | 285 | "出去玩? 能上哪儿玩” 我觉得这里无聊透顶。 286 | 287 | "找我们new 出来的对象玩去" 288 | 289 | 我想到了之前联系过我的 对象Account@659e0bfd , 想着去看看也不错。 290 | 291 | 292 | 293 | 这个叫"堆"的大楼更加拥挤, 全是人, String 的对象当然最多,Stirng类左右逢源,不停的打招呼, 从我创建出来的Account对象几乎找不到。 294 | 295 | 296 | 297 | 一队全副武装的士兵不停的在巡逻, 时不时的把对象拉出来,塞到车里去。 298 | 299 | 300 | 301 | “这是在干嘛啊” 我问String类 302 | 303 | "这些人叫清理者, 专门清理没有用的对象, 你看,车里那不是Account@659e0bfd 吗" 304 | 305 | "啊? 昨天我还和他联系, 他怎么会没用了呢" 306 | 307 | "他很有可能只是个方法的局部变量, 方法结束后, 就没人引用了, 白白的占用空间, 你看这楼太拥挤了, 如果不清理, 很快就会住满,系统崩溃, Out Of Memory了" 308 | 309 | 310 | 311 | "那这个楼就不能盖的更高点吗?” 我心里有点可怜这些被回收的对象们 312 | 313 | "楼有多高,是由码农们决定的, 他们在启动虚拟机的时候会指定参数" 314 | 315 | 316 | 317 | "那士兵咋知道谁有用没用?" 318 | 319 | "引用计数呗, 如果对象被使用, 计数就会增加, 不用的时候就会减少, 如果是0 , 那就可能被清理了。" 320 | 321 | 322 | 323 | "那我们会被清理掉吗?" 我担心的问 324 | 325 | String类神秘的笑了下: "我应该不会, 但是你是有可能的" 326 | 327 | 我当然明白了, String类是核心员工, 而我只是从外边加载过来的一个类而已, 不过我也确实有点想我的家了。 328 | 329 | 330 | 331 | 果然,又过了10天, 0x3704才动弹了一下,问我要第二条指令 332 | 333 | 我想都没想就告诉了他:“iload_1” 。 334 | 335 | 接下来又是10天的长假。 336 | 337 | ## 第五回 真相大白 338 | 339 | 漫长的调试假期终于结束了,我刚回到自己的工作间, 发生了更奇怪的事情, 整个世界毫无征兆的消失了。 340 | 341 | 342 | 343 | 我晕晕乎乎,发现还是躺在自家床上, 我是做了一场梦吗? 344 | 345 | 可是过去的记忆如此的真切, 到底是怎么回事? 346 | 347 | 348 | 349 | 管它呢, 我已经知道了自己所在的房子的门牌号是 C:\workspace\myTaobao\bin\com\mytaobao\domain 350 | 351 | 探索一下吧,唉 , 大部分人都非常无趣,不理我。 352 | 353 | 354 | 355 | 正当我准备要回去接着睡觉的时候, 我先发现了C:\workspace\myTaobao\src\ 下也有个一模一样的目录com\mytaobao\domain,关键是里边竟然有个Account.java ! 356 | 357 | 出生的模糊记忆告诉我, javac 就是从这里把我生成的。 358 | 359 | 360 | 361 | 我正要给他打招呼,一个"hi"还没说出口。 362 | 363 | javac 又一次运行, 我被新的Account.class 残忍的覆盖掉了! 364 | 365 | 366 | 367 | 临死前, 我终于明白了,这是一个码农的电脑,码农在开发程序, 调试程序, 不断的重启服务器。 368 | 369 | 而我这个类隐藏着一个Bug, 经过调试后被发现, 然后Fix了! 370 | 371 | 特别感谢: 网友blindingdark 提供的形神具备的配图, 这可是先在纸上手绘, 然后扫描变成图片, 最后用画笔涂改出来的啊 :-) 372 | 373 | ## 作者 374 | 375 | “码农翻身” 公共号 : 由工作15年的前IBM架构师创建,分享编程和职场的经验教训。 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Code-farmers-turn-over 2 | 码农翻身 3 | 4 | 作者 5 | “码农翻身” 公共号 : 由工作15年的前IBM架构师创建,分享编程和职场的经验教训。 6 | 7 | ![码农翻身](http://mmbiz.qpic.cn/mmbiz/KyXfCrME6UKLftzvWlN3oR05geqH6MtfPTCHRUTNwIq3iaqjAQOQcUW7IZkgNzfLoozFHSWzdkxgnQlbw0k9DCQ/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 8 | 9 | 10 |
大话编程
11 |
我是一个线程
12 |
我是一个Java 13 | class
14 |
Javascript: 15 | 一个屌丝的逆袭
16 |
Java:一个帝国的诞生
17 |
JSP:一个装配工的没落
18 |
TCP/IP 19 | 之 大明王朝的邮差
20 |
TCP/IP 21 | 之 大明内阁
22 |
TCP/IP 23 | 之 蓟辽督师
24 |
CPU 25 | 阿甘
26 |
CPU 27 | 阿甘之烦恼
28 |
CPU 29 | 阿甘:函数调用的秘密
30 |
我是一个网卡
31 |
我是一个路由器
32 |
我是一个进程
33 |
我是一块硬盘(上)
34 |
我是一块硬盘(下)
35 |
我是一个键盘
36 |
张大胖的socket
37 |
张大胖学递归
38 |
学习面向对象的令狐冲
39 |
张大胖学数据库
40 |
数据库村的旺财和小强
41 |
小李的数据库之旅(上)
42 |
小李的数据库之旅(下)
43 |
漫画:什么是机器学习
44 |
那些烦人的同步和互斥问题
45 |
IE为什么把Chrome和火狐打伤了
46 |
对浏览器村的第二次采访
47 |
节约标兵IE的自述
48 |
EMail 49 | 诞生记(上)
50 |
EMail 51 | 诞生记(下)
52 |
Http 53 | 历险记(上)
54 |
Http 55 | 历险记(下)—Struts的秘密
56 |
动物王国的面向对象
57 |
冯·诺伊曼计算机的诞生
58 |
Http 59 | Server: 一个差生的逆袭
60 |
张大胖的加法器
61 |
从1加到100:一道简单的数学题挑战下你的大脑
62 |

63 |
两个程序的爱情故事
64 |
两个程序的爱情故事(续)
65 |
烂代码传奇
66 |
机房夜话
67 |
干掉状态:从session到token
68 |
张大胖的docker之路
69 |
从SOA到微服务
70 |
XML的传奇人生
71 |
从密码到token, 72 | 一个授权的故事
73 |
编程世界的那把锁
74 |
加锁还是不加锁,这是一个问题
75 |
这个动物园, 76 | 两年也逛不完
77 |
张大胖和CAP定理
78 |
一个翻译家族的发家史
79 |
张大胖和单元测试
80 |

81 |
编程语言
82 |
Javascript: 83 | 一个屌丝的逆袭
84 |
计算机语言之战
85 |
我和编程语言的爱恨情仇(上)
86 |
我和编程语言的爱恨情仇(下)
87 |
Android为什么选择了Java?
88 |
iOS为什么选择了Objective-C?
89 |
Basic 90 | :一个老兵的自述
91 |
Node.js 92 | :我只需要一个店小二 只用一个线程来处理所有请求,事件驱动编程
93 |
命令式编程 94 | vs 声明式编程
95 |
编译还是解释?
96 |

97 |
程序人生
98 |
15年编程生涯,资深架构师总结的7条经验
99 |
架构师小赵
100 |
师兄说
101 |
师姐说
102 |
小王的架构师之路
103 |
小李的版本管理系统
104 |
小超穿越记
105 |
小李的Build之路(上)
106 |
小李的Build之路(下)
107 |
张大胖改Bug
108 |
我的编程之路—大学趣事
109 |
码农小王的一天
110 |
小李在外企
111 |
张大胖的需求估算
112 |
从厨师到码农
113 |
聊一聊那些神一样的程序员们(上)
114 |
聊一聊那些神一样的程序员们(中)
115 |
聊一聊那些神一样的程序员们(下)
116 |
谁是互联网之父?
117 |
一个价值百万的创业教训
118 |
让自己与众不同—提升工作的价值
119 |
看看你的“易燃性”
120 |
从无聊的工作中寻找价值
121 |
什么样的学生适合报考计算机?
122 |
谈谈程序员的职业方向(上)
123 |
谈谈程序员的职业方向(中)
124 |
谈谈程序员的职业方向(下)
125 |
谈谈培训班的作用
126 |
码农需要知道的“潜规则
127 |
学习编程的加速度
128 |
码农在工作中必备的能力
129 |
码农和英语
130 |
一声叹息
131 |

132 |
老司机经验
133 |
假如时光倒流,我会这么学Java
134 |
假如我是计算机系老师
135 |
学会编程,而不是学会Java
136 |
从增删改查中突围
137 |
抽象:程序员必备的能力
138 |
懒就一个字
139 |
编程的自学方法
140 |
小王买房记
141 |
从一道面试题谈谈一线码农应该具备的基本素质
142 |
想写框架的看过来
143 |
苹果手机变砖头以后
144 |
如何快速的学习一门技术
145 |
唯一不变的是变化:谈谈微信应用号
146 |
什么是企业应用?
147 |
为什么说远离企业应用开发?
148 |
勿以浮沙筑高台
149 |
为什么敏捷开发难于成功?
150 |
localhost 151 | vs 127.0.0.1
152 |
GitHub/Stackoverflow 153 | 找工作时有什么用?
154 |
动词 155 | or 名词 :这是一个问题
156 |
如何选择入门语言
157 |
有时候,沉默是金
158 |
零Bug代码怎么炼成的?
159 |
浮点数为什么不精确?
160 |
文章错误大全
161 |
Open 162 | Source—不要为了开源而开源
163 |
一不留神,代码就腐化了
164 |
先做个“键盘侠”,再来写程序
165 |
不加断点调试的程序员是好程序员:思考, 166 | 不看代码的思考, 是最好的调试方式。
167 |
码农必备技能:烂代码的处理之道(上)
168 |
码农必备技能:烂代码的处理之道(下)
169 |
学习数据结构有用吗?
170 |
从现在开始,丰富你的简历
171 |
那些永不过时的书,你看过几本?
172 |
学好编程必备的一个品质你知道吗?
173 |

174 |
你最爱的Java
175 |
搞懂了这几点,你就学会了Web编程
176 |
Spring本质系列(1) 177 | -- 依赖注入
178 |
Spring本质系列(2) 179 | -- AOP
180 |
三层架构和MVC那点事儿
181 |
Java帝国之拨云见日识回调
182 |
小张的Duck 183 | Typing
184 |
JDBC的诞生
185 |
JDBC后传
186 |
一个不安分的JDBC驱动
187 |
Java帝国之 188 | Java Bean(上)
189 |
Java帝国之 190 | Java Bean(下)
191 |
Java帝国之 192 | 函数式编程(上)
193 |
Java帝国之 194 | 函数式编程 (下)
195 |
关于Java初学者需要知道的10件事
196 |
Junit你不知道的那些事儿
197 |
Java 198 | EE的历史
199 |
Java 200 | EE读书指南
201 |
给小白的Java 202 | EE指南(1)
203 |
给小白的Java 204 | EE指南(2)
205 |
给小白的Java 206 | EE生存指南(3):XML
207 |
给小白的Java 208 | EE生存指南(4):一只叫TOM的猫
209 |
给小白的Java 210 | EE指南(5):AJAX
211 |
给小白的Java 212 | EE生存指南(6):Java反射
213 |

214 |
什么是框架?
215 |
学习Java虚拟机没用? 216 | 听听当事人是怎么说的!
217 |
聊聊Java 218 | 平台上的非Java语言
219 |
Java 220 | 帝国之消息队列
221 |
Java帝国之JMS的诞生
222 |
Java帝国之单例设计模式
223 |
对Java 224 | Inputstream的一次采访
225 |
ASM: 226 | 一个低调成功者的自述
227 |
序列化: 228 | 一个老家伙的咸鱼翻身
229 |
Java 230 | IO 的自述
231 |
JDK先生最近有点烦
232 |
什么是框架(续)?
233 |
说“空话”,做实事: 234 | 谈谈多态
235 |
Kotlin初体验
236 |

237 |

238 |
闲聊
239 |
饿了么初体验
240 |
来自大脑的控诉
241 |
一个高中生是怎么玩自媒体的?
242 |
尝试“分答”
243 |
到底应不应该上培训班?
244 |
自学编程中遇到问题怎么办?
245 |
据说99%的初级程序员看完后都不迷茫了
246 |
一行代码引发的“血案”
247 |
对一个死锁问题的思考
248 |
通过外包进入名企
249 |
请开往十年前的今天
250 |
为什么自学中最好有个师傅指导一下?
251 |
这个网站值得你花时间投入
252 |

253 |
编程感悟
254 |
看看“悲催”的码农得学多少东西?
255 |
学习编程的四兄弟
256 |
那些年,我后悔没做好的事情
257 |
我为什么对后端编程情有独钟?
258 |
当我们在学习编程语言时,我们在学习什么?
259 |
编程需要多少数学知识?
260 |
想成为编程高手,一定要学汇编吗?
261 |
你必须要理解的计算机核心概念
262 |

263 |
职场
264 |
我所尊敬的三位女程序员
265 |
凡事必先骑上虎背,给性格内向的程序员聊几句
266 |
我们向印度人学习什么?
267 |
你去下家面试,怎么评价你在这家公司做的工作?
268 |

269 |
开发流程
270 |
你的需求是怎么描述的?
271 |
白话敏捷软件开发
272 | --------------------------------------------------------------------------------