Dynamic allocation from memory pools

Most of the state in a KCML program resides in statically allocated objects declared with DIM or in stack based objects declared with LOCAL DIM. Thus there are a finite number of variables known in advance. This makes it very difficult to utilize data structures such as lists which require the dynamic allocation of memory from some sort of heap. Such objects have to be tracked and disposed of in a timely way.

Memory pools provide a way to manage objects that are dynamically allocated using the NEW keyword. These objects can be strings, structures, arrays or object handles. They are identified by an opaque numeric identifier that can act as a pointer when building data structures like lists and can be dereferenced using a FLD() or SYM(*) function. When a particular dynamic object is no longer required then it can be disposed of using DELETE PTR() For example:


// list element
DEF STRUCT node
    FLD nextptr AS PTR(X$_node)                   // chain pointer
    FLD payload$ AS PTR                           // dynamically allocated string
END STRUCT

// list header
DEF STRUCT list
    FLD firstptr AS PTR(X$_node)                  // points to first node in chain
    FLD lastptr AS PTR(X$_node)                   // points to last node in chain
END STRUCT

'main()
STOP
DEFSUB 'main()
    LOCAL DIM mylist$_list
    LOCAL DIM i, n
    // put some nodes in a chain
    FOR i = 1 TO 3
        n = NEW _node
        // insert at start of list
        IF (i == 1)
            FLD(mylist$.lastptr) = n
        END IF
        FLD(n.nextptr) = FLD(mylist$.firstptr)
        FLD(mylist$.firstptr) = n
        // fill in the payload
        REDIM FLD(n.payload$) = $PRINTF("node %d", i)
    END FOR

    // print out the chain
    n = FLD(mylist$.firstptr)
    WHILE n DO
        PRINT FLD(n.payload$)
        n = FLD(n.nextptr)
    WEND
END SUB

In this example we create a chain of three dynamically allocated nodes each containing a chain pointer FLD declared as type PTR and some data, in this case a dynamically allocated string.

Memory pools are associated with the stack and each function potentially has a pool associated with it. Because a form allocates space on a stack when it is opened, forms also have memory pools associated with them. The memory pool for a function or form is automatically freed up, together with all its objects, when the function or form exits and all references to the objects in the pool become invalid. This means that memory pools only exists in the context of functions. There is no default global memory pool though a mechanism is provided to allow you to create such pools in appropriate cases using CREATE POOL.

In general you can just use the default pool but because any object allocated with NEW is automatically deallocated when a function returns, you must explicitly nominate the pool to be used when allocating memory that must persist beyond the function. An example might be a function that adds an element to an existing list which must use the pool containing the list for all the elements of the list. All pools have a handle identifying them and the default pool at any time can be found with GET POOL. This could be stored with the list and used in the optional USING clause of NEW but it is simpler to just quote the name of the list structure as in:

	newnode = NEW _node USING mylist$

This is possible because a DEFSTRUCT object remembers the allocating pool internally. Structures that will be dynamically allocated or have dynamicall allocated fields should be defined with DEFSTRUCT rather than DEFRECORD as only the former will initialize the fields correctly.

Creating and managing lists by hand can be tedious and error prone so KCML provides a Collections API to simplify the task.

See also

NEW
DELETE PTR
POOL