     START-INFO-DIR-ENTRY
     * GNUstep Zones: (gnustep-zones).       Memory management in GNUstep.
     END-INFO-DIR-ENTRY

This explains how to use dynamic memory allocation with the GNUstep base library.

Copyright (C) 1997 Yoo C. Chung and Free Software Foundation, Inc.

Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.

Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.

Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.

Memory Management in GNUstep
****************************

This explains how to use dynamic memory allocation when using the GNUstep Base Library.

Memory Management
*****************

GNUstep uses zones for dynamic memory allocation.

Memory Management Concepts
==========================

A program does not always know how much memory it needs for its data (in fact, this is the case in most programs).  One might statically allocate (this means that the amount of memory is determined at compile time) memory with some large size, but this can be either a huge waste or memory might run out.  So memory must be allocated at runtime in these cases.  This is called dynamic memory allocation.

Memory returned by a dynamic memory allocator is usually called a memory block or a memory chunk.  Here we call them memory chunks.

Introduction to Zones
=====================

Any reasonably complete C library will contain the functions malloc and free.  One uses these functions for dynamic memory allocation in many C programs.  These functions usually use all of the memory for potential allocation.  This could result in two memory chunks being allocated far from each other in the virtual memory space, which could lead to increased paging.

Zones can be used to allocate many related memory chunks close to each other.  A zone is an area (actually a set of areas) in memory where related chunks of memory can be allocated from.  This might help in reducing paging on virtual memory systems.  Each zone can have different behavior (see Zone Customization).

The GNUstep Base Library uses zones for dynamic memory allocation.  The functions that are used to obtain memory chunks from zones are thread safe.

Creating Zones
==============

In order to use a zone, it must first be created.  You create zones with NSCreateZone, which is declared in NSZone.h.

 -- Function: NSZone* NSCreateZone (size_t START, size_t GRAN, BOOL CANFREE)
     Creates a memory zone which starts with a size of at least START bytes and grows by at least GRAN bytes when needed.  If CANFREE is YES, then memory chunks allocated in the zone can be freed.  If CANFREE is NO, then memory chunks allocated in the zone cannot be freed unless the whole zone is recycled, nor can they be resized.  A pointer pointing to the newly created zone is returned.

     If START is zero, the zone will start out with some default size. If GRAN is zero, the zone will grow by some default number of bytes when the zone needs more memory.

     If there isn't enough memory to create the zone, a NSMallocException is raised.

We might want to use a zone that cannot free memory chunks in a situation where we need to allocate many chunks of memory and free them all at once after using them by recycling the zone (see Recycling Zones), since a zone that cannot free memory chunks allocates memory faster than one that is able to free memory chunks.  This is because a zone that cannot free memory chunks has a lot less bookkeeping to worry about.

You do not have to explicitly create a zone to dynamically allocate memory, since there already exists a default zone.  A pointer to the default zone can be obtained with NSDefaultMallocZone, which is also declared in NSZone.h.

 -- Function: NSZone* NSDefaultMallocZone (void)
     Returns the default memory allocation zone.  The default default zone cannot be recycled.

Allocating Memory Chunks
========================

In order to allocate a memory chunk from a zone, we need to use NSZoneMalloc, which is declared in NSZone.h.

 -- Function: void* NSZoneMalloc (NSZone *ZONE, size_t SIZE)
     Allocate SIZE bytes from the zone pointed to by ZONE.  A pointer to the allocated memory chunk is returned.

     If SIZE is zero NULL is returned.  If there is not enough memory to allocate SIZE bytes, a NSMallocException is raised.

The contents of the allocated memory are uninitialized and unpredictable.  We can allocate memory filled with zeroes with NSZoneCalloc, which is also declared in NSZone.h.

 -- Function: void* NSZoneCalloc (NSZone *ZONE, size_t ELEMS, size_t BYTES)
     Allocate memory for ELEMS elements (each of which are BYTES bytes) from the zone pointed to by ZONE.  The memory chunk is initialized with zeroes.

     If either ELEMS or BYTES is zero, NULL is returned.  If there is not enough memory for the request, a NSMallocException is raised.

One should not depend on NSZoneMalloc and NSZoneCalloc returning NULL when the request size is zero.  It's bad style, not to mention that this might change in the future, or might behave differently on custom zones (see Zone Customization).

The zone containing a memory chunk allocated by NSZoneMalloc or NSZoneCalloc can be found with NSZoneFromPointer (see Finding Zones).

Resizing Memory Chunks
======================

Sometimes one doesn't know how large a memory chunk one might need in advance.  For example, if a memory chunk is a buffer for a line from a file, then no matter how large the buffer is, there might always be line that won't fit into the buffer.

One can resize a memory chunk by using NSZoneRealloc, which is declared in NSZone.h.

 -- Function: void* NSZoneRealloc (NSZone *ZONE, void *PTR, size_t SIZE)
     Resizes the memory chunk pointed to by PTR to SIZE bytes. If the memory chunk needs to be relocated, then the original contents will be copied to the new location.  PTR may be NULL, in which case a new memory chunk will be allocated from the zone.  The pointer to the resized memory chunk is returned.

     If SIZE is zero, the memory chunk pointed to by PTR is freed.  If there is not enough memory to resize the chunk, a NSMallocException is raised.

One shouldn't depend on NSZoneRealloc freeing the pointer with a size argument of zero or allocating a new chunk with a pointer argument of NULL, because it's bad style (in my humble opinion).

Freeing Memory Chunks
=====================

A memory chunk may no longer be needed after it is used.  Then it would be better to free the memory chunk so it can be reused for other memory allocation requests.  A memory chunk can be freed with NSZoneFree, which is declared in NSZone.h.

 -- Function: void NSZoneFree (NSZone *ZONE, void *PTR)
     This frees the allocated memory chunk that PTR points at.  The memory chunk must have been allocated from the zone pointed to by ZONE.

Note that unlike the C library function free, calling NSZoneFree with a pointer argument of NULL is an error.

Finding Zones Containing a Memory Chunk
=======================================

Sometimes one might need to find out the zone that contains a memory chunk.  For example, objects derived from NSObject usually need to find out the zone it resides in to deallocate itself.  One can find the zone with NSZoneFromPointer, which is declared in NSZone.h.

 -- Function: NSZone* NSZoneFromPointer (void *PTR)
     Finds the zone that contains the memory chunk pointed to by PTR and returns a pointer to it.  PTR must be a pointer returned by NSZoneMalloc or NSZoneRealloc.

NSZoneFromPointer takes a constant amount of time regardless of how many zones or memory chunks there are, so it would save space to use NSZoneFromPointer instead of saving the zone separately.

Recycling Zones
===============

A zone can become useless after a while.  Then it would be better to recycle the zone to save memory.  This can be done with NSRecycleZone, which is declared in NSZone.h.

 -- Function: void NSRecycleZone (NSZone *ZONE)
     This function recycles the zone.  All memory in the zone will be reclaimed.

Note that when a zone in GNUstep are recycled, all memory in the zone will be recycled, unlike zones in the Foundation Kit of OpenStep, where zones that can free memory return live objects to the default zone.

Naming Zones
============

Memory allocation zones can be named.  You might want to do this as a debugging aid.  You can set the name of a zone with NSSetZoneName and obtain the name of a zone with NSZoneName, which are declared in NSZone.h.

 -- Function: void NSSetZoneName (NSZone *ZONE, NSString *NAME)
     This sets a name for the zone pointed to by ZONE.  If NAME is nil, the name of the zone will be unset if there was a name previously set.  Otherwise a copy will be made of NAME in the default zone, and the name of the zone will be set to the copy.

 -- Function: NSString* NSZoneName (NSZone *ZONE)
     Returns the name for the zone pointed to by ZONE.  Don't release it unless you have retained it.

Customization
=============

The behavior of memory allocation zones can be customized in GNUstep, unlike zones with the Foundation Kit of OpenStep, which has a fixed default zone and only two kinds of zones possible.

Setting the Default Zone
------------------------

Initially there is a default default zone.  But the performance of the default allocator might not be satisfactory for a program.  In such cases, you may want to change the default zone to a zone that has more satisfactory performance.  You can do this with NSSetDefaultMallocZone, which is declared in NSZone.h.

 -- Function: void NSSetDefaultMallocZone (NSZone *ZONE)
     This sets the default memory allocation zone to the zone pointed to by ZONE.

You shouldn't change the default zone unless you know what you're doing.

Note that NSSetDefaultMallocZone is not defined by OpenStep.

Creating Custom Zones
---------------------

A zone with a custom behavior and implementation can be created.  For example, all memory chunks allocated within a zone may have the same size, in which case a much more simpler allocator than the default one can be used.

A custom zone can be created by appropriately setting the members of the structure NSZone (actually this is a typedef to struct _NSZone), which is declared in NSZone.h.

 -- Data Type: NSZone
     This is actually a typedef to struct _NSZone.  This structure contains the following members, all of which must be set to be properly used as a zone.

     void *(*malloc)(NSZone *ZONE, size_t SIZE)
          This is a pointer to the function that allocates SIZE bytes from the zone pointed to by ZONE.  (see Allocating Memory)

     void *(*realloc)(NSZone *ZONE, void *PTR, size_t SIZE)
          This is a pointer to the function that resizes the memory chunk pointed to by PTR, which was allocated from the zone pointed to by ZONE, to SIZE bytes.  (see Resizing Memory)

     void (*free)(NSZone *ZONE, void *PTR)
          This is a pointer to the function that returns the memory chunk pointed to be PTR to the zone pointed to by ZONE.  (see Freeing Memory)

     void (*recycle)(NSZone *ZONE)
          This is a pointer to the function that recycles the zone pointed to by ZONE.  (see Recycling Zones)

     BOOL (*check)(NSZone *ZONE)
          This is a pointer to the function that checks the integrity of the zone that is pointed to by ZONE.  (see Zone Consistency Checking)

     struct NSZoneStats (*stats)(NSZone *ZONE)
          This is a pointer to the function that returns statistics about the zone pointed to by ZONE.  (see Zone Statistics)

     size_t gran
          This holds the granularity of the zone.  (see Creating Zones)

     NSString *name
          This points to the name of the zone.  (see Naming Zones)

To create the functions that a zone uses, you'll probably have to use NSZoneRegisterChunk and NSZoneChunkOverhead, which are also declared in NSZone.h.

 -- Function: void* NSZoneRegisterChunk (NSZone *ZONE, void *CHUNK)
     This registers the memory chunk pointed to by CHUNK so that NSZoneFromPointer will work (see Finding Zones).  A pointer to the beginning of the memory that should actually be returned to the user is returned.

 -- Function: size_t NSZoneChunkOverhead (void)
     This returns the overhead that is needed for NSZoneFromPointer (see Finding Zones) to work in bytes.

Creating a custom zone could be an error prone process, so don't use them unless you know what you're doing (and willing to go through a potentially long debugging process).

Note that NSZoneRegisterChunk and NSZoneChunkOverhead are not defined in OpenStep.

Zone Consistency Checking
=========================

You can check the integrity of a zone by using NSZoneCheck, which is declared in NSZone.h.

 -- Function: BOOL NSZoneCheck (NSZone *ZONE)
     Checks the integrity of the zone pointed to by ZONE.  Returns YES if there are no errors, returns NO otherwise.

Note that NSZoneCheck is not defined in OpenStep.

Zone Statistics
===============

You can obtain statistics about a zone with NSZoneStats which returns the statistics in a struct NSZoneStats.  These are declared in NSZone.h.

 -- Data Type: struct NSZoneStats

     This structure type is used to return statistics about a zone, and has the following members:

     size_t bytes_total
          This is the total size of memory managed by the zone, in bytes.

     size_t chunks_used
          This is the number of memory chunks in use in the zone.

     size_t bytes_used
          This is the number of bytes in use.

     size_t chunks_free
          This is the number of memory chunks that are not in use.

     size_t bytes_free
          This is the number of bytes managed by the zone that are not in use.

 -- Function: struct NSZoneStats NSZoneStats (NSZone *ZONE)
     This returns statistics about the zone pointed to by ZONE in a structure of type struct NSZoneStats.

Note that NSZoneStats (and obviously struct NSZoneStats) is not defined in OpenStep.

Summary
=======

Here is a summary of the functions and data types that work with memory allocation zones, which are all declared in NSZone.h:

NSZone* NSCreateZone (size_t START, size_t GRAN, BOOL CANFREE)
     Creates a zone.  (see Creating Zones)

NSZone* NSDefaultMallocZone (void)
     Returns the default zone.  (see Creating Zones)

void* NSZoneMalloc (NSZone *ZONE, size_t SIZE)
     Allocates memory from a zone.  (see Allocating Memory)

void* NSZoneCalloc (NSZone *ZONE, size_t ELEMS, size_t BYTES)
     Allocates memory initialized with zeroes from a zone. (see Allocating Memory)

void* NSZoneRealloc (NSZone *ZONE, void *PTR, size_t SIZE)
     Resizes a memory chunk that had been allocated from a zone. (see Resizing Memory)

void NSZoneFree (NSZone *ZONE, void *PTR)
     Returns a memory chunk to the zone.  (see Freeing Memory)

NSZone* NSZoneFromPointer (void *PTR)
     Finds the zone that contains a memory chunk.  (see Finding Zones)

void NSRecycleZone (NSZone *ZONE)
     Recycles a zone.  (see Recycling Zones)

void NSSetZoneName (NSZone *ZONE, NSString *NAME)
     Sets a name for a zone.  (see Naming Zones)

NSString* NSZoneName (NSZone *ZONE)
     Returns the name for a zone.  (see Naming Zones)

void NSSetDefaultMallocZone (NSZone *ZONE)
     Set the default zone.  (see Setting Default Zone)

void* NSZoneRegisterChunk (NSZone *ZONE, void *CHUNK)
     Function used in custom zones to register a memory chunk. (see Creating Custom Zones)

void* NSZoneChunkOverhead (void)
     Function used in custom zones to find overhead for each memory chunk. (see Creating Custom Zones)

BOOL NSZoneCheck (NSZone *ZONE)
     Checks the integrity of a zone.  (see Zone Consistency Checking)

struct NSZoneStats NSZoneStats (NSZone *ZONE)
     Returns statistics about a zone.  (see Zone Statistics)

NSZone
     Typedef to struct _NSZone, which is a structure type that actually holds the zone.  (see Creating Custom Zones)

struct NSZoneStats
     Structure type used to return statistics about a zone.  (see Zone Statistics)