DEV Community

Cover image for AntDB Memory Management - Memory Context
AntDB
AntDB

Posted on

AntDB Memory Management - Memory Context

1. Topic description

AntDB's uses the memory context mechanism to implement memory management during its development. In this article, we will analyze the processing principle of memory context through AntDB's memory context mechanism.

In AntDB's code, when it comes to memory processing, you will often see the following code.

Example of switching memory contextsFigure 1: Example of switching memory contexts

Also this kind of code.
Requesting memory in a memory contextFigure 2: Requesting memory in a memory context

This is not quite the same as the usual way of memory operation in developing C/C++ programs, and more or less raises some doubts:

  • What is the meaning of MemoryContextSwitchTo before and after the memory operation?

  • Why does this memory context have to be switched back and forth? When do we need to switch?

  • The palloc function just calls a function pointer, what function actually implements it?

  • Why do I often only see memory request operations, but not release operations? Where does the memory request go? Is it okay not to release it?

The following contents are to explain this memory context for you.

2. What is memory context?

A memory context is a memory management mechanism. In layman's terms, a memory context can be seen as a collection of memory blocks and the methods that operate on them. For example, there is a memory context called MemoryContextA. If the user switches to MemoryContextA, then the next operations will follow at least the following two rules.

The requested memories all belong to MemoryContextA and they will be deleted with the deletion of MemoryContextA.

How to manipulate the operational memory (request, release, reallocate, etc.) is performed by the methods defined by MemoryContextA.

In AntDB, there are many memory contexts, and a tree relationship will be established between them as shown in Figure 3 below. (There are actually sibling relationships between the same layer, and those sibling relationships are not identified in this figure in order to highlight the tree hierarchy)

tree hierarchy of memory contextFigure 3: tree hierarchy of memory context

3. Why memory context is introduced?

Developers of C/C++ programs are certainly familiar with memory operations (especially memory request/release operations), of which memory leaks are a common occurrence. Especially when we develop a large software (system), it is quite challenging to use the traditional memory operation method to ensure that the memory operation will not go wrong, and it will also requires more development cost.

With the introduction of the memory context mechanism in AntDB, we don't have to care about every memory request/release, and it makes memory management clearer, easier and more reliable.

How memory context mechanism is implemented?

Now it's time to illustrate the code that we all like most. This time, we will take AntDB's code as an example to illustrate how memory context is implemented.

3.1 The most basic data structures

MemoryContextData and MemoryContextMethods are the two most basic data structures in the memory context mechanism. The definitions are shown in Figure 4 below (only specific members are described, other variables can be described by referring to the code).

MemoryContextData and MemoryContextMethods<br>
Figure 4: MemoryContextData and MemoryContextMethods

※1: This structure is just a collection of pointers and is not implemented. Developers can provide their own set of implementations based on this framework. AntDB has also installed a set of generic implementation: AllocSetMethods. Also the implementation of GenerationMethods and SlabMethods is provided, but these two need to be used in specific scenarios. The descriptions that follow are based on the premise of AllocSetMethods.

3.2 Generic Implementation of AllocSetContext

AntDB provides a generic memory context implementation: AllocSetContext. Almost all memory operations in the code are handled through this type of memory context.

Take a look at the definition, as shown in Figure 5 below.

AllocSetContextFigure 5: AllocSetContext

3.2.1 Memory operations

First, let's take a look at the members of header. From Figure 5, we can see that the methods related to memory operations are stored in the members of header; in addition, the member variables used to construct the tree relationship of the memory context, such as parent, firstchild, etc., are all inside the header.

The following memory operations can be provided by the memory context.

  • AllocSetAlloc: memory request

  • AllocSetFree: memory release

  • AllocSetRealloc: memory reallocation

  • AllocSetReset: memory context reset

  • AllocSetDelete: memory context deletion

  • AllocSetGetChunkSpace: check the size of the memory chunk

  • AllocSetIsEmpty: check if the memory context is empty

  • AllocSetStats: get the status information of memory context

  • AllocSetCheck: check all memory

3.2.2 Memory block

Let's see where the actual memory of memory context is located. Take a look at figure 6.

!the actual memory block of memory context](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/91culcfd7gxi9qw1f6fl.png)Figure 6: the actual memory block of memory context

All memories of memory context are stored in the members of blocks, which is a chain table. Memory contexts request memory in blocks (also known as big memory), one big memory at a time. The requested blocks are added to the AllocSetContext's chain table of blocks.

AllocSetAlloc, the memory request function provided by the memory context, allocates memory to the user in chunks (also called small memory). That is, the block is divided into chunks as needed and the address of the chunk is provided to the caller. What we get when we call the palloc function is the address of a memory chunk.

3.2.3 The overall structure of the memory context instance

The two important members of the memory context, header and blocks, have been introduced separately. We can now draw a general picture of a memory context instance in our mind. Please refer to Figure 7 below.

the overall structure of a memory context instanceFigure 7: the overall structure of a memory context instance

4. How to use memory contexts

Before using memory context, you need to create it first. Some memory contexts are already created and initialized when AntDB starts, for example, TopMemoryContext. This TopMemoryContext is the parent or ancestor node of all memory contexts. Generally the memory contexts we create are below the child level of the TopMemoryContext. After creation, the memory context can be used by palloc/palloc0. You can release the memory context when you are done using it.

4.1 Create a memory context

We create a memory context through AllocSetContextCreate, which is a macro-definition. The actual processing is completed by AllocSetContextCreateInternal.

the definition of AllocSetContextCreateInternal funtionFigure 8: the definition of AllocSetContextCreateInternal funtion

・Parent: the memory context that needs to be specified a parent node by us, which is set appropriately by the program.

・Name: the name of the memory context.

・minContextSize: the minimum size of the memory context.

・initBlockSize: the original size of the memory context.

・maxBlockSize: the maximum size of the memory context.

The emoryContextCreate function will be called to create the memory context in the end.

4.2 Splitting memory use in memory contexts

Before requesting memory you need to consider: in which memory context the current memory should be requested. Different memory contexts are used for different purposes and have different life cycles. After deciding on a memory context, the MemoryContextSwitchTo function is called to switch to the target memory context.

The role of the MemoryContextSwitchTo function is to switch to the target context and return the current memory context. For general usage, please refer to:

Current memory context = MemoryContextSwitchTo(target memory context)

Perform memory request and other operations. At this time, the requested memory is in the target context.

Handle the logic according to your own code, and switch back to the current memory context in time if needed.

MemoryContextSwitchTo(current memory context)

Improper or untimely switching of memory contexts can lead to unexpected consequences, or even crash the program directly. A very simple example is shown in Figure 9.

example of improper switching of memory contextFigure 9: example of improper switching of memory context

Once we have decided on the memory context we need to use, we can call the memory allocation function palloc/palloc0 to request memory. Note one thing, palloc0 will initialize all the memory to 0 after it finishes requesting memory, while the content of the memory requested by palloc is indeterminate. Both of these functions are ultimately implemented by AllocSetAlloc.

When the memory is used up, pfree can be called to free it. This function points to the AllocSetFree function. In AntDB, it is not necessary to call pfree to free the memory of palloc either. The freeing of memory can be left to the freeing phase of the memory context.

Of course there are various other memory-related operations, realloc, reset, etc. The functions they point to are listed in the previous section 3.2.1.

4.3 Freeing a memory context

After a memory context is determined to be no longer in use, you can call MemoryContextDelete to delete the memory context. If you just want to free some memory chunks in the memory context, you can call pfree to free some of the memory. Note that this pfree operation only returns the memory to the memory context, not to the operating system. AntDB also provides a memory reset function, which frees all memory blocks (except for those specifically set to be reserved, the contents of the reserved memory blocks will be cleared).

5. Conclusion

This time, we have briefly introduced the basic concept of memory context. We hope that after reading it, you will have some basic understanding of memory context and will not be so unfamiliar with similar code in the future. At the same time, I believe you have the answers to the doubts raised at the beginning of this article.

Of course, there is still a lot of knowledge about memory contexts that has not been written out, such as: what the role of the other member variables in the structure; what is the process of creating a memory context; what is the process of requesting memory and what are the algorithms and so on. Also, what are the potential issues of memory context; are there any parameters to control the size of memory context; what AntDB's continuous improvement of memory context will be ...... we will continue to share with you slowly in the next articles. (First the concept, then the details. This article is the process of establishing the concept, and then it will be easier to understand when we talk about the details.)

Finally, a little advice for all database fans and technology enthusiasts. We need to experiment and debug by ourselves to digest what we read into our own knowledge. Welcome to follow AntDB and explore and grow together with us in the world of database.

Top comments (0)