本章涉及到两个问题,其一是数据空间技术,目标是减少程序所需数据的存储空间;其二是代码空间技术,目标是减少执行期间保存程序时所用的内存。
数据空间技术
不存储,重新计算。 如果我们在需要某一给定对象的任何时候,都对其进行重新计算而不保存,那么保存该对象所需的空间就可以急剧地减少。此方法牺牲更多的运行时间来换取更少的空间。这种方法只适用于需要“存储”的对象可以根据其描述重新计算得到的情况。
对于许多跨网络运行的程序来说,在数据规模方面我们最关心的是传输数据需要花费的时间。有时我们会采纳“保存、不进行重新传输”的建议,通过本地缓存的方式减少需要传输的数据量。
稀疏数据结构。 稀疏数据结构可以通过只存储数据的有效部分大大减少存储所需空间。使用指针来共享大型对象也可以消除存储同一对象的众多副本所需的开销,但是程序员在修改共享对象时必须小心谨慎地确保该对象的所有拥有者都希望修改。一些电话系统将语音会话看作为稀疏结构以节省通信带宽。当某一方向上的音量下降到临界水平时,采用简洁的表示法来发送静音;节省下来的带宽可以用来传送其他的会话。
数据压缩。 信息理论告诉我们,可以通过压缩的方式对对象进行编码,以减少存储空间。比如可以用c=10×a+b将两个十进制数a和b编码在一个字节中。解码时可以采用
a = c / 10 b = c % 10
或者采用位运算提高速度:c=(a<<4) | b。解码:
a = c >> 4 b = c & 0xF
信息理论还指出,我们可以压缩通过某一通道(比如磁盘文件或网络)发送的记录流。
分配策略。 动态分配通过在需要时才对记录进行分配的方式,避免了对存储空间的浪费。可变长记录的策略是指,当确实需要请求某样东西时,我们应该根据需要量来请求。
垃圾回收。 对废弃的存储空间进行回收再利用,从而那些不用的位就可以重新使用了。在现代计算系统中,使用对高速缓存敏感的内存布局非常重要。
代码空间技术
函数定义。 通过用函数替换代码中的常见模式可以简化程序,相应地也就减少了它的空间需求,并增加了其清晰性。这是一个“自底向上”的方法。尽管我们不能忽视自顶向下的方法,但是由良好的原始对象、组件和函数所给出的均一视图可以使系统维护起来更加简单,同时也节省了空间。
解释程序。 用较为简短的解释程序语句可以代替较长的程序文本,这一技术的采用可以减少代码代码长度。
翻译成机器语言。 在节省空间方面,大多数程序员都较少控制的是将源语言转换成机器语言。对编译器进行一些微小更改可以将Unix系统早期版本的代码空间减少5个百分点。作为最后的手段,程序员可能会考虑到将大型系统中的关键部分用汇编语言进行手工编码。这个高开销、易出错的过程仅能带来一点好处。
原理总结
空间开销。 如果程序使用的内存增加10%,有的系统中可能感觉不到变化,非常小的系统中程序可能会因为内存溢出而运行不了。如果数据需要在网络中传输,传输的时间可能会增加10%。在一些缓存和分页系统中,运行时间可能会急剧增加,因为先前与CPU较接近的数据现在已经逆行到二级高速缓存、RAM或磁盘中了。
空间的“热点”。 在程序的“热点”中,少部分的代码经常要占用大部分的运行时间;对于代码所需的内存来说则相反:无论一条指令执行了多少次,它需要的存储空间都一样。事实上数据也可以具有热点:少数常见类型的记录经常要占用大部分的内存。
空间度量。 多数系统都提供了性能监视器,允许程序员观察程序运行时内存的使用情况。
折中。 有时程序员必须牺牲程序的性能、功能或可维护性以获得内存,这样的工程决策应该在所有可选办法都研究过之后才能做出。
与环境协作。 编程环境对程序的空间效率具有重要影响。重要的环境因素包括编译器和运行时系统所使用的表示方式、内存分配策略以及分页策略。
使用适合任务的正确工具。 当内存很重要时,考虑上述所有可能的选项。