In openvpn, a good memory management solution is based on the linked list. The implementation of this solution uses a gc_arena structure, the function of this struct is to collect all dynamically allocated memory blocks and release them in one place. The disadvantage of C for dynamic memory management is that dynamic memory cannot be tracked, therefore, the management of dynamic memory is handed over to the programmer, and then there are countless bugs caused by memory leakage. Although C ++ implements many memory management solutions, for example, smart pointers and so on, but the complexity is not limited to the heavyweight Language C ++ itself, making the complicated language more bloated with a specific library, in addition, the dynamic memory management implemented in C ++ is nothing more than the use of constructor, destructor, and so on. The specification is quite complicated. If someone thinks it is not complicated, then he is either a beginner C ++ or a person who has learned C but has not learned C well.
If we talk about this topic, dynamic memory management is not very complicated. The only technical difficulty is to track the allocation of dynamic memory, rather than the specific release time, once all the dynamic allocation is successfully tracked, the release time is the programmer's business. Previously, the programmer could not track the dynamic memory allocation and lead to memory leakage. This is not a programmer's fault, after all, the bigger the program, the more uncontrollable it is, and not everyone is a master. But if you get all the memory allocated at the moment, but it is still leaked, it is your personal problem, therefore, you only need to make a summary of dynamic memory allocation. The memory management solution of openvpn is to skillfully organize the dynamically allocated memory into a linked list, and then uniformly release the memory at the right time. This release does not release a memory block, instead, all the memory blocks collected are released. First, let's take a look at the infrastructure of this mechanism:
Struct gc_entry {// One-way linked list of GC Mechanism
Struct gc_entry * next;
};
Struct gc_arena {// The Most Important outer structure. The GC mechanism is built on it.
Struct gc_entry * List;
};
Static inline struct gc_arena gc_new (void)
{// Allocate a GC. Note that it is inline. Otherwise, the buffer on the stack is returned incorrectly.
Struct gc_arena ret;
Ret. List = NULL; // Initialization
Return ret;
}
Static inline void gc_free (struct gc_arena *)
{// Release of the linked list, releasing all dynamic memory areas on the linked list
If (a-> List)
X_gc_free ();
}
Void x_gc_free (struct gc_arena *)
{// Specific release action
Struct gc_entry * E;
E = A-> list;
A-> List = NULL;
While (E! = NULL) {// The elements of the traversal table, which are released one by one
Struct gc_entry * Next = e-> next;
Free (E );
E = next;
}
}
Void * gc_malloc (size_t size, bool clear, struct gc_arena *)
{// Important allocation functions
Void * ret;
If (){
Struct gc_entry * E; // note that the size of the allocated space must be added with the size of gc_entry. gc_entry is responsible for management.
E = (struct gc_entry *) malloc (size + sizeof (struct gc_entry ));
Check_malloc_return (E );
Ret = (char *) e + sizeof (struct gc_entry); // only the memory excluding the management data is returned to the caller
E-> next = A-> list; // link the block of memory to the linked list.
A-> List = E;
}
...
If (clear) // allocate a clear 0 memory
Memset (Ret, 0, size );
Return ret;
}
The above code is clear. The following is an example of using the above mechanism:
Int mmalloc (struct gc_arena * GC)
{// If the following is changed to malloc (1000), it will be finished in an instant.
Char * Buf = (char *) gc_malloc (1000, 1, GC );
}
Int main (INT argc, char ** argv)
{
Struct gc_arena GC = gc_new ();
GC. List = NULL;
Int I = 0, j = 0;
While (1 ){
I ++;
While (J ++ <10 ){
Mmalloc (& GC );
}
J = 0;
Gc_free (& GC );
}
}
What is the "right" time? When will it be released? This is actually a question. The answer is that you need to know it by yourself. That is to say, you must know when the allocated buffers are useless. What this GC mechanism does is to help you collect all the buffers, instead of deciding the release time for you, if you understand the counter mechanism of Linux kernel, it will certainly be amazing for this memory management mechanism, but to be honest, even the counter mechanism requires the programmer to determine when to call free, while the counter is decreasing in free. What the counter mechanism does for you is to control the number of paths that the counter is currently using this memory, when to release the memory, you still need to control it by the programmer. In fact, you should not covet any cost-free automatic memory management mechanism, nor do you have such a mechanism, currently, there are two main types of memory management mechanisms to be implemented: C ++ uses mechanisms such as constructor and destructor at the cost of simplicity, it is actually implemented using some fixed C ++ standards, and the other is a garbage collection mechanism that sacrifices performance and controllability. Java uses this method, the Java Virtual Machine needs to maintain an object reference diagram and regularly triggers Garbage collection removes the free graph node memory. It can be seen that the only thing that does not need to pay the system price is the implementation of C, but the programmer needs to pay the price when writing code, no matter what, in simple terms, I would rather use the C method than C ++ or Java's seemingly simple and actually bloated method.