保持C/C 程式代码的可伸缩性

2008-02-23 05:24:11来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

  在今天,已有许多的32位应用程式感到,在32位平台上可用的虚拟内存受到了一定的限制,对程式研发者来说,即使是开始关注64位平台时,也不得不维护软件的32位版本,这就需要一种方法,以使代码的两个版本都保持相当的可伸缩性。

  现在的内存剖析工具能帮助确定,当程式达到峰值内存使用量时,都发生了什么,但是这些工具都过于关注已分配的内存块,而不是已提交的虚拟内存地址空间,而这两种衡量标准没有直接的相关性,如内存泄漏、内存碎片、内存块内的空间浪费、或过度延迟的内存单元重新分配这些因素,都会导致不必要的虚拟内存提交。运行时分析工具如IBM Rational Purify或Parasoft Inuse均能够提供内存泄漏及已用内存的描述,这些信息是很有用的,但是,一个特别的内存块也许可能、也许不可能影响到虚拟内存覆盖区,另外,甚至一个有碎片的内存堆中的一个小块,也能直接影响到虚拟内存覆盖区。从另一方面来说,在此范围内的任意内存块--甚至泄漏的块,对虚拟内存覆盖区来说,也不会和之有什么关系,除非每一个此范围内有用的内存块能重新分配到一个更紧凑的范围内,这就有点像Java或托管程式的垃圾回收机制,但对大多数C/C 本地应用程式来说,就绝对不可能了,因为在虚拟内存空间中,他们内存块的位置是不确定的。

  至于本地代码,不必要的虚拟内存使用,这个实际的问题,比未清理的内存块这个理论上的问题,更加有实质性。未清理的内存块可能导致虚拟内存的浪费,造成过多的系统开销,但或不会;这完全依赖于堆管理器是否提交了更多的虚拟内存,以支撑这种浪费。某些很小的未使用的内存块,不会引起不必要的堆"扩展"。和其让您来猜哪一个或多少已浪费的内存块导致了堆扩展,倒不如学会怎样判定出有意义的浪费是什么。当堆中包含不再使用的内存块时,此时通过加入对未缩减堆的检查,就能确定出和您的程式虚拟内存需要有很大关系的、必须进行的内存块清理。

  为找出哪一个堆中的内存块需多留意,必须在程式中加入一些额外的代码,以跟踪内存堆范围及已分配的内存块。对额外的代码进行条件编译,生成一个特定的版本,也许是个不错的办法。

  为达到此目的,需编写自定义的内存分配例程,并跟踪每一个内存块,另有一个自定义的释放例程,且跟踪虚拟内存中堆的位置,请参见例1和例2的伪代码算法。可能还需编写自定义的访问函数以标记出访问过的内存块,以便于在适当的时候释放虚拟内存,任何这些并无需过多的内存开销。另一方面,假如您的程式以堆的形式使用了大量的内存,那么将会极大地降低性能,此处的方法也不是长久之计。

  例1:

/* 输入参数*/
ADDRESS triggerAddr
SIZE triggerSize
LIST a list of tracked heap ranges

IF (the virtual memory at triggerAddr is tracked on the list as part of a heap range)
DO
IF (triggerAddr triggerSize >
(the tracked upper boundary of that heap range))
DO
/* 一个现有的堆范围被扩展 */

make system call(s) to determine the base and extent of the newly committed range that contains the addresses from triggerAddr to (triggerAddr triggerSize)

update the size of the tracked heap range to indicate its new upper limit
END
END
ELSE DO
/* 在triggerAddr中有一个新的堆范围 */

make system call(s) to determine the base and extent of the newly committed range that contains the addresses from triggerAddr to (triggerAddr triggerSize)

track the new committed range in the list of heap ranges
END

  例2:

/* 输入参数 */
ADDRESS triggerAddr
SIZE triggerSize
LIST a list of tracked heap ranges

/* 局部变量 */
ADDRESS origRangeBase
SIZE origRangeSize
BOOL bFoundChange

bFoundChange = FALSE

IF (the virtual memory at triggerAddr is not tracked on the heap range list as part of a heap range)
DO
/*似乎我们已清楚此次释放了。*/
END
ELSE IF (an access exception occurs when memory at triggerAddr is read)
DO
bFoundChange = TRUE
END

IF (bFoundChange) DO
/*因为之前内存块占用的空间被释放了,所以堆占用的虚拟内存范围就改变了。*/

make system calls to determine the bases and extents of the tracked committed heap ranges in the immediate vicinity of the decommitted range that includes the addresses from triggerAddr to (triggerAddr triggerSize)

/*更新堆范围跟踪,以反映剩余提交的范围 */

IF (any portion of the tracked heap range that contained the block at TriggerAddr is still committed)
DO
update the heap range list to track just the portion(s) of that range that remain committed
END
ELSE
DO
delete the list element that tracks the range
END
END



[1] [2] 下一页

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇: 浅议C 中的垃圾回收方法

下一篇: C 的救赎 C 开源程式库评话

热门词条
热门标签