All Manuals > LispWorks User Guide and Reference Manual > 10 Storage Management > 10.2 Guidance for control of the storage management system


10.2.3 Long-lived data

Long-lived data is data that lives long enough to be promoted to the highest generation to which promotion occurs automatically (the "blocking generation"), but later becomes garbage. The blocking generation is 2 in 32-bit LispWorks and (by default) 3 in 64-bit LispWorks.

You can check which generation individual objects are in (by generation-number), but normally you want to know the total amount of data in various generations. The function room is used for that. In general, it is useful to call


and sometimes also

(room t)

periodically (every 5 minutes) and log the output. In servers, such logs are essential. From this output you can see how the sizes of the various generations change over time.

If the output shows that the blocking generation grows too much, even though permanant data is not added, you will need to do something about it. In 64-bit LispWorks there is a good chance that you do not have to do anything. In 32-bit LispWorks long-lived processes (for example servers) probably need to do something.

The main thing you will do is calling (gc-generation t) . This garbage collects the blocking generation. You should check the state of the memory after calling it by calling room again. If the amount of allocated data (as opposed to total size) did not reduce, you may have a memory leak that causes accumulation of permanent data that does not die.

If gc-generation does free data (that is, the allocation reduces significantly), you probably need to add calls to it to your application.

Comptibility note: In 32-bit LispWorks version 5.1 and earlier, the documented way to collect generation 2 is to call (mark-and-sweep 2) . (gc-generation t) does what (mark-and-sweep 2) does, plus some additional operations that improve the perfomance of allocation. It also has the advantage that it is the same call that is used in 64-bit LispWorks. We recommend always using gc-generation.

To decide when to call gc-generation, you need to consider the following:

  1. You need to prevent excessive growth of the process.
  2. You want to avoid calling gc-generation when the application needs to respond quickly.
  3. The call will be more effective if it is done between chunks of work than in the middle of a chunk of work.

We now discuss these considerations in detail:

  1. You can follow the overall size of the process by looking at the output of (room nil) , or programmatically by using the result of room-values. The definition of "excessive growth" depends on the machine that you are running on and what the server actually does. Normally you want to avoid the need for paging, so you should try to keep the size of the image below the size of real memory that it can use. For 32-bit LispWorks on modern machines that have a lot of memory, the limit will be the amount of address space the machine has. In addition, garbage collecting a larger image takes more time. In a typical 32-bit application, 100-200Mb would be the target, though it can be larger. In a 64-bit application the limit is the size of the real memory.
  2. (gc-generation t) can take a significant amount of time. 32-bit LispWorks on a modern machine can collect 100-200Mb in less than a second if it does not page. If it pages, or has a slower CPU, it takes more time. The 64-bit GC is generally faster and better, as long as it does not page, but since you normally deal with much more data in 64-bit images, there may be significant delays in 64-bit LispWorks. If such delays are a problem for your application, you should try to call gc-generation at times when it is less of a problem. Use time to find out how long gc-generation takes in various situations.
  3. If you can identify places where there are no active chunks of work, you can try to place calls to gc-generation in these places. For servers, this is likely to be much less important than the two considerations above, but for an application that computes results using large amounts of data, this may be a significant consideration.

In 32-bit LispWorks, by default, generation 2 (which is the "blocking generation") is not collected automatically, because such collection may take a signficant amount of time, so most programmers need to control when it actually happens. You can change this by using collect-generation-2, but usually you need better control, and do a collection of generation 2 when it is appropriate. Therefore if your application generates long-lived data, you need to add calls to gc-generation.

Even if you find that your application does not generate long-lived data (that is, generation 2 does not grow), it is probably a good idea to keep checking, in case some circumstances do cause it to generate long-lived data.

In 64-bit LispWorks by default generation 3 (the "blocking generation") is collected automatically, so there is a good chance that you do not have to do anything. However, you may want to call gc-generation explicitly when you know it is a good time to do it. You may also want to block automatic calls if they they take too long: use set-blocking-gen-num to do that. If generation 3 becomes very big (Gigabytes), you may also consider using marking-gc instead of gc-generation.

Once you set up gc-generation calls, you may still see the image growing even though the allocation does not grow that much. That is normally the result of fragmentation. On 32-bit LispWorks you can use check-fragmentation to check for fragmentation, and try-move-in-generation to prevent it if needed. See Controlling Fragmentation for a discussion.

In 64-bit LispWorks you have a problem with fragmentation only if you use marking-gc. marking-gc has keyword arguments that can be used to reduce fragmentation, and there is a good chance that using these will be enough to avoid serious fragmentation. gc-generation can be used occasionally to eliminate all fragmentation. Check for fragmentation by using gen-num-segments-fragmentation-state.

LispWorks User Guide and Reference Manual - 21 Dec 2011