• 编程中的冰山理论从 RPM 改变文件大小说起
  • 心得

编程中的冰山理论——从 RPM 改变文件大小说起

你能看到的只是表面很少的一部分——冰山理论。

在编程排查问题时,我们经常遇到的情形就是,看似一个很小的点,深究起来却发现其背后隐藏着更深层次的技术逻辑。昨天的上线经历让我深有体会。

昨日上线,一切如旧。云淡风轻,茶香四溢。

焚香,沐浴,更衣,食素三日之后总该一切无忧了吧。

用 RPM 包在线上解包完成,轻泯了一口茶水,正准备手起键落重启服务。电光火石之间,感觉命运之神轻拍了一下我的肩膀:“还差点什么吧?” “额,好像是的,重启之前最好再得对比下文件内容,确保传输过程没问题”。例行公事而已,简直有些画蛇添足。

然而,对比文件内容之后,却发现 RPM 解包后得到的可执行文件和打包前文件的 md5 不一样。

RPM 打包没报错,传输没报错,解包没报错。

看看文件大小,打包前可执行程序14M,但包中解出来的却只有900多 K,相差甚多。

这是打包前:

这是解包后:

处理过程没报错,但是文件内容不一样,一定是没看好,传错RPM包了。重新检查 spec 文件,重新打包,重新传输,每一步都小心翼翼。

解包之前先对比下RPM包的md5 吧。很好,这次传对了,两个RPM 包一样,刚才一定是传错文件了。

解包,品茗,手起键落,准备重启。又一次电光火石,感觉肩膀又被命运之神拍了一下。“好吧,再给你个面子”,对比一下可执行文件。

历史总是惊人的相似,解包后还是912 k。打包前14M,解包后大小缩减了这么多。

再来:打包没报错,传输没报错,解包没报错。但解出来程序却变小了,一定是幻觉。又对比了两次,幻觉依旧。

你信或不信,事实就在那里。各个过程都没错,可是就变小了。思考逻辑与事实的冲突,恐怕是最折磨人的吧。

过程没错,但文件却大小变化了,心中默念多次之后,突然想到:谁说文件变小了一定是错误?

对啊,变小不一定是错误。那一定是谁在某个过程中做了什么手脚。上面已经验证,传输前后RPM包内容一样,那只能是RPM在打包或解包时做了什么操作了,并且rpm 在做这个操作时没有报告。

决定从就从打包过程开始排查。打包输出信息中有这么几行:

strip,objdump,我们好像在哪见过。依稀记得strip 好像是用来去掉可执行文件中调试信息的,objdump 是用来处理可执行文件的。正好我程序中含有调试信息,那么会不会是rpm 调用的strip 把调试信息自作主张的去掉了呢?毕竟rpm 包通常是release 版本,调试信息的作用不大,自动删除也是有可能的。

曙光初现。用file 命令看一下解包后的文件信息:

”not stripped“ ,文件没有被strip。欲哭无泪,不禁想起了一句话—— 前途是光明的,道路是曲折的。

调试信息还在,那变小的原因是什么?你到底少了什么?!

调整心情,从头再来,一条路不行,再尝试另外一条路。创建包时的输出信息中,除了strip,还有objdump。这两个都是处理二进制可执行文件的。建包和解包都没有报错,但文件变小了,那少的只能是程序运行时无用的信息,无用的信息又只能是调试信息和无用的符号之类的,而file 显示额外信息还在,没被strip 掉。还在,还在。

又默念了多次之后,突然又灵光一闪:谁说strip信息还在就等于调试信息没变化呢?

strip 信息还在,并不代表调试信息没变化。思维定势害死人啊。那就看看打包前和解包后两个可执行文件中的调试信息数量有没有区别。

抱着试试看的心理,用如下命令把两个可执行文件中的调试信息写到了文件中:

objcopy --only-keep-debug rubik_superfst info.dbg

这是打包前程序生成的调试信息大小:

这是解包后程序生成调试信息大小:

这里写图片描述

果然不一样!已经隐约见到胜利灯塔上闪现的微光了。file 命令的障眼法,还是被我给瞧破了。

调试信息大小不一样,那么RPM 到底去除了哪些信息呢?看看objcopy 还有什么使用方法。

man objcopy 

发现 objcopy 的参数中有好几个 strip 开头的选项:

既然是调试信息大小不一样,我们就先在打包前的程序上试试去除调试信息的选项 –strip-debug,即 -g 选项。

objcopy -g rubik_superfst

看看打包前的程序在执行这一命令后发生了哪些变化:

一次无意的尝试,竟获得了意想不到的结果。在未打包程序上执行完 objcopy -g 得到的文件,竟然和RPM 包解包后变小的程序完全一样。这说明了什么?这说明了 RPM 做的操作就是执行了 objcopy -g 命令!

既然调试信息还是被 strip 了,那么就 google 一下如何保留调试信息吧。只要在 spec 文件中加入:

%define __strip /bin/true

万事大吉。再对比打包前和解包后的可执行文件,md5 完全一样。

一切如旧。云淡风轻,茶香四溢。

RPM,终究你还是没逃出我的掌心。食素、焚香、沐浴、更衣,终究是有用的。

那么,file 命令为什么对已经去掉了调试信息的程序还会显示 “not stripped” 呢?file 命令的 man page 中并没有对 strip 进行明确的说明。发现上面 objcopy 命令有好几个strip 选项,那就试试吧。

梦想还是要有的,万一实现了呢?尝试的勇气还是要有的,万一有发现新大陆呢?

先看 strip-all 选项,这个看上去是去除了所有无用信息,应该对 file 有效:

果然有效!但是 strip-debug 对file 命令就无效,用gdb查看时,strip-all 也删除了调试信息的符号,看来strip-all 中应该还删除了除调试符号外的其他符号,而 file 命令关注的就是这些内容。感兴趣的同学可以继续研究。本篇就不做扩展了。

心得

  • 别看现在闹得欢,小心将来拉清单。别高兴的太早,码农前进的路上从来不缺的就是坑。
  • 排除掉所有不可能的因素,剩下的即使再不可思议,也是真实答案。
  • 吾爱吾师,但吾更爱真理。这个spec 文件是根据前辈使用的文件改进的,本来觉得万无一失,没想到还是会有一些问题。
  • 世事洞明皆学问。文件大小变化看似是一个不起眼的小问题,但抽丝剥茧深究起来还真的学到不少东西。
  • bug 一定有线索。要重视程序的输出或log,及早发现bug 的线索在排查问题时能节约不少时间。
  • 排查问题时一定要深度思考,不要病急乱投医,东试一下,西试一下。想清楚当前问题的症结在哪,从症结出发一步步前进,直至找到问题的最根本原因。
  • 跳出思维定势,跳出思维定势,跳出思维定势。换个角度考虑问题会有不一样的收获。

我就是我,疾驰中的企鹅。

我就是我,不一样的焰火。

编程中的冰山理论——从 RPM 改变文件大小说起相关推荐

  1. 编程中的数学理论——排列数组合数

    目录 Part 1 引入 Part 2 排列数 Part 3 组合数 Part 4 总结 Part 1 引入 在一开始,我们需要了解所以方案问题求解的两个原理--加法原理&乘法原理. 加法原理 ...

  2. 计算机理论在实际编程中的应用之我见

    计算机理论在实际编程中的应用之我见   自毕业后很长一段时间里,我一直认为在大学时学的计算机理论跟实际应用是脱节的,毕业后的这几年里,基本上没有用到这些,用到的只是些类库及api等等,直到最近我想开发 ...

  3. 【转】游戏编程中的人工智能技术--神经网络

    原文:http://blog.csdn.net/ecitnet/article/details/1799444 游戏编程中的人工智能技术 . > .  (连载之一) 用平常语言介绍神经网络(Ne ...

  4. 数据科学和机器学习中的优化理论与算法(下)

    数据科学和机器学习中的优化理论与算法(下) 数据科学和机器学习当前越来越热,其中涉及的优化知识颇多.很多人在做机器学习或者数据科学时,对其中和优化相关的数学基础,包括随机梯度下降.ADMM.KKT 条 ...

  5. 从“冰山理论”看无代码开发与用户的科学分工

    冰山理论是美国萨提亚家庭治疗中的重要理论,实际上是一个隐喻,它指一个人的"自我"就像一座冰山一样,我们能看到的只是表面很少的一部分--行为,而更大一部分的内在世界却藏在更深层次,不 ...

  6. 游戏编程中的人工智能技术--神经网络

    游戏编程中的人工智能技术 . <神经网络入门> .  (连载之一) 用平常语言介绍神经网络 (Neural Networks in Plain English) 因为我们没有很好了解大脑, ...

  7. 游戏编程中的人工智能技术

    游戏编程中的人工智能技术 转自http://blog.csdn.net/aifuture/article/details/1852030 分类: 神经网络 2007-10-28 17:44 652人阅 ...

  8. Windows用户界面编程中的界面闪烁问题

    http://yyf9989.cnblogs.com/archive/2005/09/02/228320.html Windows用户界面编程中的界面闪烁问题 南京千里独行版权所有转载请保留本信息 在 ...

  9. 向量几何在游戏编程中的使用

    <1>简单的2-D追踪 -Twinsen编写 -本人水平有限,疏忽错误在所难免,还请各位数学高手.编程高手不吝赐教 -我的Email-address: popyy@netease.com ...

最新文章

  1. yolo-mask的损失函数l包含三部分_【AI初识境】深度学习中常用的损失函数有哪些?...
  2. 根据条件单元格的值改变单元格的显示色块和文字颜色等属性。
  3. c5.0 java_机器学习-AdaBoosting及其Java实现
  4. ASP.NET多种不同页面间数据传递的方法
  5. leetcode 202. Happy Number
  6. 经典题:poj2104-区间第k小 整体二分学习
  7. 【HDU - 1257】最少拦截系统 (标解dp,贪心可过,最长上升子序列类问题)
  8. spark学习-37-Spark的SortShuffleManager
  9. 超级有用的git reset --hard和git revert命令
  10. html半圆形,【实例】CSS3画一个半圆的方法
  11. 【网络实验】10G网络下的真实带宽——CPU负载与网卡TSO、GSO
  12. RocketMQ读写队列
  13. 禁止ubuntu更新内核
  14. MATLAB中颜色模型介绍级各模型之间转换(RGB、HSV、NTSC、YCbCr、HSI)
  15. Markdown入门学习小结
  16. 光场相机 标定微透镜阵列
  17. window中关于端口被占用的解决443 failed: port is already allocat
  18. Back-off restarting failed container报错
  19. 湖北计算机技术以考代评,目前有哪些专业技术资格即职称实行“以考代评”?...
  20. Java项目:基于java航空订票系统(计算机毕业设计)

热门文章

  1. 404计算机考研,考研404 上岸
  2. CMS建站平台Java版-Jeeplus cms
  3. qwt-QwtPlot
  4. LED学习及一个花样流水灯的实现
  5. 基于微信小程序的实验室管理系统Postmorterm
  6. 遥感影像处理书籍推荐
  7. 《静态页面爬虫》读后总结
  8. 探究PBR的两种流程以及Unity中的PBS
  9. [置顶] iOS中 支付宝钱包详解/第三方支付
  10. Html顶部导航栏实现