- 我是一个线程(修订版)
- 我是一个 Java class
- Javascript:一个屌丝的逆袭
- Java : 一个帝国的诞生
- JSP 一个装配工的没落
- TCP/IP 之 大明王朝邮差
- TCP/IP 之大明内阁
- TCP/IP 之蓟辽督师
- CPU 阿甘
- CPU 阿甘之烦恼
- CPU 阿甘:函数调用的秘密
- 我是一个网卡
- 我是一个路由器
- 我是一个进程
- 我是一块硬盘(上)
- 我是一块硬盘(下)
- 我是一个键盘
- 张大胖的 socket
- 张大胖学递归
- 学习面向对象的令狐冲
- 张大胖学数据库
- 数据库村的旺财和小强
- 小李的数据库之旅(上)
- 小李的数据库之旅(下)
- 漫画:什么是机器学习?
- 那些烦人的同步和互斥问题
- IE 为什么把火狐和 Chrome 给打伤了?
- 对浏览器村的第二次采访
- 节约标兵 IE 的自述
- EMail 诞生记
- Email 诞生记(下)
- Http 历险记(上)
- Http 历险记(下)-- Struts 的秘密
- 动物王国的面向对象
- 冯·诺伊曼计算机的诞生
- Http Server : 一个差生的逆袭
- 张大胖的加法器
- 从 1 加到 100:一道简单的数学题挑战下你的大脑
- 编程语言
- Javascript:一个屌丝的逆袭
- 计算机语言之战
- 我和编程语言的爱恨情仇(上)
- 我和编程语言的爱恨情仇(下)
- Android 为什么选择了 Java
- iOS 为什么选择了 Object-C?
- Basic : 一个老兵的自述
- Node.js : 我只需要一个店小二
- 命令式编程 vs 声明式编程
- 编译还是解释?
- 程序人生
- “架构师"小赵
- 师兄说
- 师姐说
- 小王的架构师之路
- 小李的版本管理系统
- 小超穿越记
- 小李的 Build 之路(上)
- 小李的 Build 之路(下)
- 张大胖改 Bug
- 我的编程之路--大学趣事
- 码农小王的一天
- 小李在外企
- 张大胖的需求估算
- 从厨师到码农
- 聊一聊那些神一样的程序员们(上)
- 聊一聊那些神一样的程序员们(中)
- 聊一聊那些神一样的程序员们(下)
- 谁是互联网之父?
- 一个价值百万的创业教训
- 让自己与众不同 - 提升工作的价值
- 看看你的“易燃性”
- 从无聊的工作中寻找价值
- 什么样的学生适合报考计算机?
- 谈谈程序员的职业方向(上)
- 谈谈程序员的职业方向(中)
- 谈谈程序员的职业方向(下)
- 谈谈培训班的作用
- 码农需要知道的“潜规则”
- 学习编程的加速度
- 码农在工作中的必备能力
- 码农和英语
- 老司机经验
- 假如时光能够倒流, 我会这么学习 Java
- 假如我是计算机系老师
- 学会编程, 而不是学会 Java
- 从增删改查中突围
- 抽象:程序员必备的能力
- 懒就一个字
- 编程的自学方法
- 小王买房记
- 从一道面试题谈谈一线码农应该具备的基本素质
- 想写框架的看过来
- 苹果手机变砖头以后
- 如何快速的学习一门技术?
- 唯一不变的是变化: 谈谈微信应用号
- 什么是企业应用?
- 勿以浮沙筑高台
- 为什么敏捷开发难于成功?
- localhost vs 127.0.0.1
- GitHub/Stackoverflow 找工作时有什么用?
- 动词 or 名词 :这是一个问题
- 如何选择入行语言
- 有时候,沉默是金
- 零 Bug 的代码是怎么炼成的?
- 浮点数为什么不精确?
- 文章错误大全
- Open Source--不要为了开源而开源
- 一不留神,代码就腐化了
- 先做个“键盘侠”, 再来写程序
- 不加断点调试的程序员是好程序员
- 码农必备技能:烂代码的处理之道(上)
- 码农必备技能:烂代码的处理之道(下)
- 学习数据结构有用吗?
- 从现在开始,丰富你的简历
- 那些永不过时的书,你看过几本吗?
- 学好编程必备的一个品质你知道吗?
- 你最爱的 Java
- 搞懂了这几点,你就学会了 Web 编程
- Spring 的本质系列(1) -- 依赖注入
- Spring 本质系列(2)-AOP
- 三层架构和 MVC 那点事儿
- Java 帝国之拨云见日识回调
- 小张的 Duck Typing
- JDBC 的诞生
- JDBC 后传
- 一个不安分的 JDBC 驱动
- Java 帝国之 Java bean (上)
- Java 帝国之 Java bean(下)
- Java 帝国之函数式编程
- Java 帝国之函数式编程(下)
- 关于 Java 初学者需要知道的 10 件事
- JUnit 你不知道的那些事儿
- 圣诞礼物:Java EE 的历史
- Java EE 读书指南
- 给小白的 Java EE 指南
- 给小白的 Java EE 指南(2)
- 给小白的 Java EE 生存指南(3) : XML
- 给小白的 Java EE 生存指南(4) : 一只叫 Tom 的猫
- 给小白的 Java EE 指南(5) : AJAX
- 给小白的 Java EE 生存指南(6) :Java 反射
- 闲聊
- "饿了么"初体验
- 来自大脑的控诉
- 一个高中生是怎么玩自媒体的?
- 尝试 分答
- 到底应不应该上培训班?
- 自学编程中遇到问题怎么办?
- 据说 99%的初级程序员看完后都不迷茫了
- 一行代码引发的“血案”
- 对一个死锁问题的思考
- 通过外包进入名企
- 请开往十年前的今天
- 为什么自学中最好有个师傅指导一下?
- 这个网站值得你花时间投入
- 为什么你无法坚持自学编程?
我是一个 Java class
前言:本文主要想讲一下 Java 虚拟机的故事, 可能有点偏门,不妥之处欢迎留言交流。
第一回 陌生警察
我出生在 C 盘下面一个很深层次的目录下, 也不知道是谁把我放到这里的。
我一直在睡觉,外边的日出日落,风雨雷电和我一点关系都没有。
直到有一天,有个家伙咣咣咣砸我房门把我叫醒。
这个家伙穿着像警察的制服, 左手拿着一个对讲机, 右手递过来他的工作证: "你好, 我是 Classloader, 请问你是 Account 类吗"
"是啊, 怎么了?"
这个 Classloader 没回答我, 反而拿起对讲机:
"头儿,你看看你能不能装载这个 Account 类?”
对讲机那头好像也在问他的上司,过了半天,终于有了回音:
"我装载不了, 我的上级也说了,他们也装载不了, 你来干吧"
"那就报数吧~” 我这次注意到旁边站着另外一个笑眯眯的小个子。
"报什么数?" 我一脸诧异。
"唉,果然没有被装载过, 你是个 class 文件,当然要报文件开头的那几个数了, 就是 Java 他爸 James Gosling 在 jdk 1.0 时确定的那个数啊"
"奥, 我看看, 0xCAFEBABE"
"不错, 是个 java 类, 把你后边的两个数也报一下", 小个子继续问
"50 , 0"
"看来版本不高啊, 是 jdk 1.6 编译出来的啊", 小个子接着说 "最新的虚拟机都 1.8 了, 都函数式了,你造不?”
我哪里知道? 我这才模模糊糊的回想起来, 好像是有个什么 javac 把我创建出来,扔到了这个屋子里。
"现在奉命带你去 Java 虚拟机,有人需要你的帮助" , 这个 Classloader 态度冷冰冰的, 我不喜欢他。
"大哥,你们咋找到我的?" 我决定和小个子套近乎。
"那还不简单, 我们老板有个列表, 上面列举着所有应该检查的目录,我们顺藤摸瓜,一个一个找,肯定能找到"
"那万一找不到咋办?"
"基本不可能, 你看老板给我们的目录列表中有 C:\workspace\myTaobao\bin , 我们在下面再找三级 com/mytaobao/domain, 这不就找到你了吗,
Account.class , 话说回来, 万一真找不到, 将来在执行时会抛出 ClassNotFound 异常了,那不归我们管"
我后来才知道, 我的全名其实叫做 com.mytaobao.domain.Account !
"来来来, 让我验证一下, 你这 class 编译的对不对" ,小个子拿出一个放大镜
"恩, 常量池, 访问标识, 字段,方法... 看起来没有问题“ , 小个子对 Classloader 说。
被人拿着放大镜看,这种感觉极为不爽。
"走, 去虚拟机" , Classloader 还是冷冰冰的。
这哥俩不容我带任何东西, 便把我推上车,飞奔向我没听说过的“虚拟机”。
第二回 刺探信息
我感到前途未卜, 但也不能坐以待毙, 一定得多了解信息。
"大哥, 你叫什么名字" , 我看小个子还算和气。
"我就是大名鼎鼎的文件验证器了, 能管很多事"
"那刚才他为啥还得请示上级呢" , 我用眼神指了一下开车的 ClassLoader
文件验证器的声音一下子就压低了:
"你不知道,说来话长, 我们之前出现过事故,有个黑客写了个类 java.lang.String, 和我们老板手下有一个干活最卖力的员工名字一模一样,只是这个黑客类里边竟然有格式化硬盘的代码,我们的小兵 Classloader 不明就里,就把这个黑客类给先装载了,也执行了, 最后的结果,唉,很惨的... "
"那后来怎么办?"
"后来我们老板就定下了规矩:他的骨干员工像 String, ArrayList 等只能由他自己的心腹去装载, 我听说老板的心腹都是分层级的,像传销一样, 每个都有上线, 最顶层的叫 Bootstrap Classloader , 下一次级叫 Extension Classloader, 现在开车的这位其实叫 App Classloader,位于最底层, 咱这位 Classloader 在装载一个类之前,一定要问一问这几位权利极高的大爷,请他们先装载,这几位爷装载不了,才由我们这些小兵来出马。“
"这能避免黑客攻击?"
"能啊! 你想想, 那个黑客写了个攻击的 java.lang.String, 我们在装载之前,肯定要请示 Extension, Bootstrap 这些大爷先来装载, 由于 String 是老板的核心员工,肯定会他们先装载啊, 这些大爷把 String 直接就给我们了, 我们就不会装载黑客类了"
“你能不能少说两句” Classloader 似乎生气了。
我和文件验证器只好禁声。
其实文件验证器也不是只会给我吹牛, 他也很敬业, 这家伙在车上把我全部的字节码都要了过去, 对这些天书一般的东西一遍一遍的检查分析,确保每个指令都是正确的, 检查是不是有超类, 是不是覆盖了 final 方法,跳转指令是不是正确....
第三回 初识虚拟机
很快我们就来到了目的地, 我一看虚拟机不就是几个大楼嘛, 不过这几座大楼可真是高啊。
他俩把我带进其中一座叫“方法区”的大楼,进了电梯, 输入 2048 。
很快来到第 2048 层, 无数的格子间平铺开来,他们七拐八拐,轻松的把我带到了我的位置, 上面写着我的名字“com.mytaobao.domain.Account”.
我问文件验证器: “这楼这么高, 这么多格子间, 人会坐满吗?”
"只有极少情况会坐满, 一旦满了,那时候会抛出异常, 我们就完蛋了。 你自己好自为之吧, 再见 "
他们把我安顿好就立刻离开了。
我往周边一看, 咦,这不是著名的 java.lang.String 吗。
我本想和他打个招呼, 可以他的电话似乎一直没断过, 嘴里一直说着什么 store, load 之类我听不懂但是似乎有点熟悉的话。
正无聊着呢,我桌子上的电话也响了, 电脑屏幕也亮了,我看到一个人对我笑着说:
"你好, 我刚刚 new 出来的 Account 对象, 我的编号是 Account[at]659e0bfd"
晕倒 ! 这家伙和我什么关系?
看我一脸的诧异, 他说,“ 很快就会有个线程到 CPU 车间了,他会联系你, 我就是想确认下你在不在, 奥对了, 我在一个叫做堆的地方, 有空找我玩啊, byebye ”, 说完就消失了。
果然没多久, 视频电话又响了。
这次我看到一个人站在一个明亮的车间里, 抱着一个包裹, 他按了一个按钮, 面前立刻升起一个工作台 , 台子上立了一个有很多抽屉的柜子,每个抽屉上都有一个编号, 旁边还有一个深桶。
(后来我就知道, 那个柜子的学名叫做 局部变量区 , 那个桶叫做 操作数栈 )
我正想问问问怎么回事呢, 就听到了他的声音:
"我是线程 0x3704, 我要调用你第二个方法了“
(注: 不认识线程 0x3704 的同学可以回复“我是一个线程”查看)
我一看, 我的第二个方法是 add :
public void add(int x , int y ){
x = x + y;
.....其他代码略....
}
(注: Account 类当然看不到这些源码, 这是为了方便你看的 :-) )
"请把第一条指令给我说一下" 0x3704 继续问我要东西
我还不太熟练,找了半天才说:
"iload_0"
于是他就操作柜子上的机械手把 0 号抽屉的一个数 30 扔到到了工作台上的一个桶里,这个桶很窄,没法并排放两个数, 但是很深。
然后 0x3704 说 “下一条指令”
"iload_1"
于是 1 号抽屉的一个数 40 也被扔到了桶里,正好压在 30 上面, 从桶上面就看不到 30 了。
“下一条指令”
”iadd“
于是他就把两个数从桶里取了出来, 做了个飞快的动作, 这两个数变成了一个数 70 !, 然后他又把 70 放到了桶里。
“下一条指令”
"istore_0"
于是他把 70 从桶里捞出来, 放到了柜子上编号为 0 的地方, 之前的 30 就被扔掉了。
我看的目瞪口呆,这厮是在干嘛???
我问他: “0x3704, 不就是把两个数加起来吗? 为啥搞的这么麻烦”
他不理我, 只是继续说, “下一条指令”
我只有配合它玩这个游戏。
java.lang.String 难得的悠闲, 端着一杯咖啡一边看我手忙脚乱的取指令, 一边说:
"新人都这样, 别着急,等你熟练了,闭着眼睛就搞定了, 就像我一样,你可能不知道 , 我们这个虚拟机叫做基于堆栈的虚拟机, 看到那个桶没有,其实就是个先进后出的栈啊, 我们虚拟机的所有指令其实都是在对栈进行操作"
可是我还是好奇: “这栈有什么好啊”
旁边的格子间的 java.util.Stack 立刻说:
"这事儿你得问我啊, 怎么说呢, 主要是为了简单, 你看我们只用一个简单的桶,奥对了,栈, 就能完成所有的工作, 你做要的就是往栈里扔东西(入栈), 然后从最上面拿东西(出栈) 就行了。 不像 intel 的 CPU, 搞了巨多的桶,每个桶只能容纳一个数, 他们还美名其曰寄存器, 做加法的时候, 先把一个数放到第一个桶, 再把另外一个数放到第二个桶,加起来以后的结果还得找个桶,有些桶还不通用,这么多桶找起来麻烦死了。 "
"可是我们的栈操作起来就麻烦了啊, 你看一个简单的加法都得操作半天" ,我不依不饶。
"我们的指令可以优化啊, 不过这我也不太懂"
这个游戏我整整完了一天,没有线程找我的时候, 我就闲着, String 说得对, 熟练以后简直太简单了。
String 就不一样了, 几乎每时每刻都线程给他打电话要指令, 这么没办法, String 确实是虚拟机的骨干和精英, 使用频繁,业务纯熟,忙而不乱。
有时候我会看到线程有不止一个工作台, 而是一摞子工作台, 也是一个压一个, 线程们都很老实,永远在最上面那个工作, 从来不会先干下面的活。
我问 java.util.Stack :"这些工作台也是栈吧"
"猜的不错,学名叫 Java 栈 ,每个线程都有一个, 其中的每个工作台你看过了 ,学名叫 栈帧 , 知道不? 每个台子都代表一个方法调用, 这一摞工作台就方法调用方法导致的啊 "
确实是, 因为我发现一旦调用新方法, 立刻就会形成一个新的工作台, 压在老的上面。 方法调用完成后, 栈顶的工作台就被销毁了, 线程会在底下的工作台继续机械的干活。
第四回 快乐假期
第二天, 0x3704 又问我要指令, 我有点生气: 你就不会记住吗
0x3704 说: 我可不能记住, 万一你被重新装载了, 指令变了怎么办?
我告诉他指令是"iload_0" , 他刚把数据扔到桶里, 古怪的事情发生了, 身手敏捷的 0x3704 突然好像凝固了一样,不动了。
只听到 String 欢呼: “遇到断点了,码农开始调试了, 我们放假了!”
"调试?什么调试?"
"就是码农会单步、手工的执行这些指令,他们慢死了, 可能一秒才能执行一步, 由于我们的时间比他们快的多, 他们的一秒,简直就是我们的 10 几天, 走, 出去玩去"
"出去玩? 能上哪儿玩” 我觉得这里无聊透顶。
"找我们 new 出来的对象玩去"
我想到了之前联系过我的 对象 Account@659e0bfd , 想着去看看也不错。
这个叫"堆"的大楼更加拥挤, 全是人, String 的对象当然最多,Stirng 类左右逢源,不停的打招呼, 从我创建出来的 Account 对象几乎找不到。
一队全副武装的士兵不停的在巡逻, 时不时的把对象拉出来,塞到车里去。
“这是在干嘛啊” 我问 String 类
"这些人叫清理者, 专门清理没有用的对象, 你看,车里那不是 Account@659e0bfd 吗"
"啊? 昨天我还和他联系, 他怎么会没用了呢"
"他很有可能只是个方法的局部变量, 方法结束后, 就没人引用了, 白白的占用空间, 你看这楼太拥挤了, 如果不清理, 很快就会住满,系统崩溃, Out Of Memory 了"
"那这个楼就不能盖的更高点吗?” 我心里有点可怜这些被回收的对象们
"楼有多高,是由码农们决定的, 他们在启动虚拟机的时候会指定参数"
"那士兵咋知道谁有用没用?"
"引用计数呗, 如果对象被使用, 计数就会增加, 不用的时候就会减少, 如果是 0 , 那就可能被清理了。"
"那我们会被清理掉吗?" 我担心的问
String 类神秘的笑了下: "我应该不会, 但是你是有可能的"
我当然明白了, String 类是核心员工, 而我只是从外边加载过来的一个类而已, 不过我也确实有点想我的家了。
果然,又过了 10 天, 0x3704 才动弹了一下,问我要第二条指令
我想都没想就告诉了他:“iload_1” 。
接下来又是 10 天的长假。
第五回 真相大白
漫长的调试假期终于结束了,我刚回到自己的工作间, 发生了更奇怪的事情, 整个世界毫无征兆的消失了。
我晕晕乎乎,发现还是躺在自家床上, 我是做了一场梦吗?
可是过去的记忆如此的真切, 到底是怎么回事?
管它呢, 我已经知道了自己所在的房子的门牌号是 C:\workspace\myTaobao\ bin \com\mytaobao\domain
探索一下吧,唉 , 大部分人都非常无趣,不理我。
正当我准备要回去接着睡觉的时候, 我先发现了 C:\workspace\myTaobao\ src \ 下也有个一模一样的目录 com\mytaobao\domain,关键是里边竟然有个 Account.java !
出生的模糊记忆告诉我, javac 就是从这里把我生成的。
我正要给他打招呼,一个"hi"还没说出口。
javac 又一次运行, 我被新的 Account.class 残忍的覆盖掉了!
临死前, 我终于明白了,这个一个码农的电脑,码农在开发程序, 调试程序, 不断的重启服务器。
而我这个类隐藏着一个 Bug, 经过调试后被发现, 然后 Fix 了!
(全文完)
特别感谢 : 网友 blindingdark 提供的形神具备的配图, 这可是先在纸上手绘, 然后扫描变成图片, 最后用画笔涂改出来的啊 :-)
声明 :原创文章,版权所有, 未经授权,不得转载。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论