• 【2019年第12周】【2019/03/18 - 2019/03/24 】
  • A. LeetCode 661
  • R: Dependency injection in Golang using higher order functions
  • T: Go 的测试
  • S: 图解 Go 内存分配器
  • S: 如何打印日志

Algorithm

Review

Tips

Share

图解 Go 内存分配器笔记

  • CPU通过控制总线,数据总线,地址总线和内存通信。

    • 数据总线:在 CPU 和内存之间传递数据的通道
    • 控制总线:在 CPU 和内存之间传递各种控制/状态信号的通道
    • 地址总线:传递地址信号,以确定所要访问的内存地址
  • 目前具有64位地址总线的 CPU(x86-64)可以寻址2的64次方,但是目前大多数 CPU 都只用了其中的48位或者42位,尽管理论上可以访问2的64次方(256TB)大小的地址空间,但是操作系统通常没有完全支持它们。

  • 系统的每个进程运行在各自的沙盒中,也就是所谓的虚拟地址空间。操作系统需要记录虚拟地址到物理地址的映射转换,也就是页表。

  • 系统在分配内存的时候,并没有申请相应的物理页帧,只有在真正赋值的时候才会申请物理页帧。这也就是 VSZ (进程虚拟内存大小) 和 RSS(物理常驻内存大小) 的最大区别

如何打印日志笔记

在程序开发的过程中,并不是所有的 bug 都是可以复现的。当我们遇到不可复现的 bug 时。 日志就成为了我们解决 bug 的一个重要参考内容。如何打印日志才能日志尽可能多地包含有效信息,而整体看起来又不是很混乱呢,感觉这篇文章中提到的一些 tips 很有参考意义。

  • 成功日志: 动词 + 一些事

为了让日志简短,我们可以把一些不必要的连词去掉(例如 to, and 等),动词的 ing 时态写在代码开始运行时,ed 时态写在代码运行后。这样日志使用 egrep 查找起来也方便一些

  • 失败日志: Fail to 动词 + 一些事

这里使用fail to的原因是,很多框架,库,编译器等产生错误时,会使用failed关键字,使用fail to可以让我们在 egrep 查询的时候更有效率。

  • 打印值

感觉使用=而不是:表示值这点很值得推广,因为:会在其他场合用到,=只会用来表示一个变量的值。一些容器类型变量可以用下面的形式,打印字典({a=1}),打印数组([1 2 3]),打印元组((1, 2, 3.14))。

  • 使用简单英语

想象这样一个场景,半夜两点你被同事打电话叫醒,告诉你线上服务挂了。 然后你问他报什么错,他把一个单词来回念了四五遍,还向你拼写了好几遍,你才反应过来这是啥。 你这时会不会想锤自己,为什么当初写日志的时候要写这么长的一个谁都不认得的单词(写日志的时候你用 Google 查了一个陌生的单词,相信我,过了两个月后你很快就会忘记这个是单词什么意思)。

  • 懂得汇总

文章中提到了很好的一点,可以把日志写入到 thread-loca 或者 session-local 中,等 Session 结束后打印汇总信息或一起打印,这样可以减少 IO 压力,也可以让日志更清晰明确。

  • 个人补充的一些 tips
  1. 对一些变量进行 clean 操作(去除掉\t, \r\n, \n等特殊字符)。之前曾经写过一个 csv 格式的日志,但是因为打印的一个变量中含有\t字符,导致解析困难,需要重新记录日志
  2. 对于一些重要的代码,可以在函数入口处打印函数的名称和参数名称。例如 Python 中可以使用 %(funcName)s 获取函数名。如果函数的参数是列表/字典等容器类型的话,可以打印出长度以及少量元素。