社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Git

首版Git源码初探——Linux之父在malloc之后也忘了free啦?

IT服务圈儿 • 1 周前 • 32 次点击  
来源丨经授权转自 经授权转自 计算机奇闻逸事

作者丨胡译胡说

Linus Torvalds 无疑是开源软件界最具影响力的人物之一。作为 Linux 内核的创始人,他因技术贡献赢得了尊敬,但也常因口无遮拦的言辞引发争议。

Linus 对代码质量的要求极其严苛,也许正是因为自信能够写出完美的代码,才让他有底气挖苦和讽刺其他开发者吧。

Linus 写出的代码到底能有多么精简、多么高深、多么优雅、多么健壮……?可能很多程序员都对此充满好奇。Linux 内核的代码显然过于复杂,不适合“鉴赏”。不过,好在 Linus 还在 2005 年 4 月(和 BitKeeper 闹翻之后)编写过 Git 的原型,而且 Git 最初版本的源代码(https://github.com/git/git/commit/e83c5163316f89bfbde7d9ab23ca2e25604af290)只有千行左右,算上 README 和 Makefile 才只有 11 个文件。这可真是揭晓答案的好机会。

  1.  $ wc -*.*.| sort

  2.    23 cat-file.c

  3.    43 read-tree.c

  4.    51 init-db.c

  5.    66 write-tree.c

  6.    81 show-diff.c

  7.    93 cache.h

  8.   172 commit-tree.c

  9.   248 update-cache.c

  10.   259  read-cache.c

  11.  1036 total

不过,要是把这些源文件通读一遍还是需要花些功夫的。那就再从中挑一个最简单的来看一看。毕竟齐白石画只虾、画个萝卜也是名作。

最简单的应该是 init-db.c 了(别光看 cat-file.c 和 read-tree.c 的行数少,那里面调用的函数可复杂了)。经过编译后, init-db.c 形成了一个叫作 init -db 的命令。

试着运行一下就会发现,该命令的功能非常单一,类似现在的 git init,仅仅是先在当前目录中创建一个隐藏目录 .dircache,然后在里面创建 objects 目录,以及以两位十六进制数命名、名称依次为 00~ ff 的 256 个子目录。

对照着功能再来欣赏下 Linus 亲自操刀的 init-db.c 的代码,

代码非常直观,①先调用 mkdir() 创建了 .dircache,然后创建了 .dircache/ objects②,最后利用 for 循环,创建了 256 个名字依次为 00~ ff 的、 .dircache/objects 中的子目录。

但请注意这一行 path=malloc(len+40);。这里动态分配了一块内存,大小为 len+40,用于存储以十六进制数命名的子目录的路径。

稍有 C 语言编程经验的程序员都会牢记一条法则,如果使用 malloc() 分配了内存,但忘记调用 free() 来释放,就会造成内存泄漏。只要大学还在使用谭浩强的 C 语言教材开蒙,就是毫无项目经验的大一新生,也会因多次听到老师强调这一点,而囫囵吞枣地记住要 free() 吧。大名鼎鼎的 Linus 竟然忘了?

而且,搜索整个项目,可以发现不止一处调用了 malloc(),calloc(),realloc() 来申请内存,

却只 free() 过 1 次!

Linus 是真忘了?这不妥妥地内存泄露吗!

等一等, malloc() 之后真的一定要 free() 吗

其实,如果程序运行时间很短(就像 init-db 这样简单的工具),程序结束后操作系统就会回收所有已分配的内存(包括未释放的堆内存),所以不手动释放也不会对系统产生显著影响(但确实是不好的编程习惯)。

而 Linus 在初版 Git 中唯一一次 free() 是在 for (i=0;i<entries;i++){ 这样一个循环中调用的。这说明即使程序不会长时间运行,但如果分配了大量内存或通过循环多次申请内存,还是应该及时 free(),及时释放资源给其他进程。


总之, malloc() 之后并不是一定需要 free(),这取决于具体的场景和需求。下回面试时万一忘记写 free(),就可以辩解了,“Linus 当初创造 Git 时也没写,我们这是特意不写的”。但结果嘛……祝你好运。

不过,还有个好奇的点, path=malloc(len+40) 这里为啥要  +40 呢,追加的 /[0-f][0-f] 明明只占 3 个字节呀。

1、网友的 Linux 桌面和我的 Linux 桌面!
2、CPU「离奇」飙到 100%!开发者挖出 Linux 内核 16 年老 Bug:这么多年竟无人发现?
3、国外大神1:1真实复刻Win11系统,真牛!
4、外包能拿30k以上的,为什么还做外包呢?
5、两周!中国开源界第一架构师横空出世!

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/178653
 
32 次点击