10.11 Controlling Fragmentation

Some applications periodically free (that is, stop using) a substantial amount of data that lived for long enough to reach generation 2 (use room or sys:room-values and sys:generation-number to follow the behaviour of objects). In this case, mark-and-sweep should be called on generation 2, to collect these data and re-use the memory. Repeated cycles like this may cause fragmentation, which will slow down promotion into generation 2. This manifests itself in significant pauses, typically of a few seconds. try-move-in-generation or try-compact-in-generation can be used to reduce the fragmentation, and hence to reduce the pauses. Because these functions themselves take some time, they should be called when such a pause is acceptable.

'Moving' a segment means moving objects out of the segment to another segment, leaving the segment empty. This reduces the fragmentation in the generation, and it is normally much faster than compact. Therefore in almost all cases, try-move-in-generation is better than try-compact-in-generation .

The actual decision to use these functions will be typically based on the results of check-fragmentation . For example, the following function checks if there is more than 10Mb free area in generation 2 in blocks of 4096 bytes or larger (tlb, third return value of check-fragmentation ). If there is not, and the free area in generation 2 (tf) is more than four times the free area in large blocks, it calls try-move-in-generation . Because try-move-in-generation gets a time-threshold of 0, it returns after doing at most one segment. (It won't do any segments if none of them looks fragmented.)


(defun call-memory-functions()
  (mark-and-sweep 2)          ; first collect all dead objects
  (multiple-value-bind (tf tsb tlb)
      (check-fragmentation 2) ; check the fragmentation
    (when  (and (> 10000000 tlb)         
                (> (ash tf -2) tlb))
       (try-move-in-generation 2 0))))


A function such as this can be called at times when a pause of a few seconds is acceptable, and it will keep the memory of generation 2 unfragmented.

It is not possible to give definitive guidance here on how to use try-move-in-generation or try-compact-in-generation , because it depends on the way the application uses memory. In general, these functions will always improve the behavior of the application. Therefore the main problem is to identify points in the execution of the application where they can be called without causing unacceptably long pauses.

LispWorks User Guide - 8 Apr 2005