|
|
As noted, only the text segment of a dynamically linked library is shared by all processes that use it; its data segment typically is not. Every process that uses a dynamically linked library usually gets a private memory copy of its entire data segment, regardless of how much data is needed. You can cut down the size of the data segment in several ways:
In some other implementations, system error messages are made available to applications only through two global variables:
extern int sys_nerr; extern char *sys_errlist[];sys_errlist[X] gives a character string for the error X, if X is a non-negative value less than sys_nerr. Now if the current list of messages were made available to applications only through a lookup table in an archive library, applications that used the table obviously would not be able to access new messages as they were added to the system unless they were relinked with the library. Errors might occur for which these applications could not produce useful diagnostics. Something similar happens when you use a global lookup table in a dynamically linked library:
static const char msg[] = { "Error 0", "Not owner", "No such file or directory", ... };The message array is static, so no application space is allocated to hold a separate copy. Because no application copy exists, the dynamic linker does not waste time moving the table. New messages can be added, because only the library knows how many messages exist. Finally, note the use of the type qualifier const to identify data as read-only. Whereas writable data is stored in the data segment of a dynamically linked library, read-only data can be stored in its text segment. For more information on const, see ``Type qualifiers'' in ``C language compiler'', and the -Krodata option to cc(CP).char strerror(int err) { if (err < 0 || err >= sizeof(msg)/sizeof(msg[0])) return 0; return (char )msg[err]; }
In a similar way, try to allocate buffers dynamically -- at run time -- instead of defining them at link time. This saves memory because only the processes that need the buffers get them. It also allows the size of the buffers to change from one release of the library to the next without affecting compatibility as shown in the following:
char buffer() { static char buf = 0;if (buf == 0) { if ((buf = malloc(BUFSIZE)) == 0) return 0; } ... return buf; }