Several implementation methods of malloc ()

Source: Internet
Author: User
Malloc () is one of the standard library functions for Dynamic Storage Management in C language. The function is to allocate a continuous space with a length of size in the dynamic storage area of the memory. The parameter is an unsigned integer, And the return value is a pointer to the starting address of the allocated continuous storage domain.


Dynamic memory allocation is a way to dynamically allocate or recycle the memory allocated to a bucket during execution. Unlike static memory allocation methods such as arrays, dynamic memory allocation requires pre-allocation of storage space. Instead, the system allocates the storage space in real time based on program requirements, and the allocated size is the size required by the program. This article briefly introduces the dynamic memory allocation function malloc () and several implementation methods.


1. Introduction


Malloc () is one of the standard library functions for Dynamic Storage Management in C language. The function is to allocate a continuous space with a length of size in the dynamic storage area of the memory. The parameter is an unsigned integer, And the return value is a pointer to the starting address of the allocated continuous storage domain. Note that a null pointer is returned when the function fails to allocate storage space (such as insufficient memory. Therefore, when calling this function, check whether the returned value is null and perform corresponding operations.


2. Function Description


The Dynamic Storage Management of C language is implemented by a set of standard library functions. The prototype is described in the standard file <stdlib. h>. These functions should be used to include this file. There are four functions related to dynamic storage allocation, including the storage allocation function malloc (). The function prototype is void * malloc (size_t n). The size_t here is a type defined in the standard library, and it is an unsigned integer. This integer can meet all the requirements for the storage block size description. The specific integer is determined by the specific C system. The return value of malloc is of the (void *) type (this is an important use of generic pointers). It allocates a block that can store data of N and returns the corresponding pointer value; if the application cannot be met (the required storage block cannot be found), null is returned. In use, the return value of malloc should be converted to a specific pointer type and assigned to a pointer.


Note: although the storage block here is obtained through dynamic allocation, its size is also determined and cannot be used across borders. For example, N pieces of double-precision data can be stored in the block allocated in the above section, and subsequent use must be performed within this range. The Dynamic Allocation of storage blocks out of the border, especially out-of-border assignment, may cause very serious consequences. It usually damages the operating system of the program and may cause the program or the entire computer system to collapse.


The following is an example of Dynamic Allocation:
# Include <stdlib. h>


Main ()
{
Int count, * array;/* count is a counter, and array is an integer pointer. It can also be understood as pointing to the first address of an integer array */
If (Array (int *) malloc (10 * sizeof (INT) = NULL)
{
Printf ("the bucket cannot be allocated successfully. ");
Exit (1 );
}
For (COUNT = 0; count <10; count ++)/* assign values to arrays */
Array [count] = count;
For (COUNT = 0; count <10; count ++)/* print array elements */
Printf ("% 2D", array [count]);
}


In the above example, 10 integer storage areas are dynamically allocated, and then assigned and printed. In this example, the IF (Array (int *) malloc (10 * sizeof (INT) = NULL) statement can be divided into the following steps:
1) allocate 10 integer continuous buckets and return an integer pointer pointing to its starting address.
2) Assign this integer pointer address to array
3) check whether the returned value is null.


3. malloc () Working Mechanism


The essence of the malloc function is that it connects available memory blocks into a long list of so-called idle linked lists. When calling the malloc function, it searches for a memory block that is large enough to meet user requests along the connection table. The memory block is then split into two parts (the size of one part is equal to the size of the user request, and the size of the other part is the remaining bytes ). Next, pass the memory allocated to the user, and return the remaining (if any) to the connection table. When the free function is called, it connects the memory block released by the user to the idle chain. At the end, the idle link will be cut into many small memory segments. If you apply for a large memory segment, there may be no fragments on the idle link that meet your requirements. Therefore, the request latency of the malloc function starts to rummaging through the idle chain to check the memory segments, sort them, and merge adjacent small idle blocks into larger memory blocks.


4. Implementation of malloc () in the operating system


In the C program, malloc () and free () are used multiple times (). However, you may not have time to think about how they are implemented in your operating system. This section will show you one of the most simplified implementation code of malloc and free to help you illustrate what is involved in memory management.


In most operating systems, memory allocation is handled by two simple functions:


Void * malloc (long numbytes): This function allocates numbytes memory and returns a pointer to the first byte.


Void free (void * firstbyte): If a pointer returned by the previous malloc is given, the function returns the allocated space to the idle space of the process ".


Malloc_init is a function used to initialize the memory allocation program. It identifies the allocation program as initialized, finds the last valid memory address in the system, and creates a pointer to the memory we manage. All three variables are global variables:


Listing 1. Global variables of our simple allocation Program


Int has_initialized = 0;
Void * managed_memory_start;
Void * last_valid_address;




As mentioned above, the mapped memory boundary (the last valid address) is often called a breakpoint in the system or a breakpoint in the current state. In many UNIX? In the system, the sbrk (0) function must be used to indicate breakpoints in the current system. Sbrk moves the breakpoint in the current system based on the number of bytes given in the parameter, and then returns the breakpoint in the new system. If the parameter 0 is used, only the current breakpoint is returned. Here is our malloc initialization code, which will find the current breakpoint and initialize our variables:




Listing 2. Allocation program initialization Function
/* Include the sbrk function */
 
# Include
Void malloc_init ()
{
/* Grab the last valid address from the OS */
Last_valid_address = sbrk (0 );
/* We don't have any memory to manage yet, so
* Just set the beginning to be last_valid_address
*/
Managed_memory_start = last_valid_address;
/* Okay, We're initialized and ready to go */
Has_initialized = 1;
}




Now, to fully manage the memory, we need to be able to track the memory to be allocated and recycled. After free calling of memory blocks, we need to mark them as unused and when calling malloc, we need to be able to locate unused memory blocks. Therefore, the starting point of each memory returned by malloc must first have this structure:




Listing 3. Memory Control Block Structure Definition
Struct mem_control_block {
Int is_available;
Int size;
};



Now, you may think this will cause problems when the program calls malloc-How do they know this structure? The answer is that they do not need to know; before returning a pointer, we will move it to this structure and hide it. This causes the returned pointer to point to memory that is not used for any other purposes. In this way, from the perspective of calling programs, all they get is idle and open memory. Then, when the pointer is passed back through free (), we only need to go back several memory bytes to find this structure again.




Before discussing memory allocation, we will discuss release first because it is easier. To release the memory, the only thing we have to do is get the pointer we give, roll back the sizeof (struct mem_control_block) bytes, and mark it as available. Here is the corresponding code:




Listing 4. unallocation Function
Void free (void * firstbyte ){
Struct mem_control_block * MCB;
/* Backup from the given pointer to find
* Mem_control_block
*/
MCB = firstbyte-sizeof (struct mem_control_block );
/* Mark the block as being available */
MCB-> is_available = 1;
/* That's it! We're done .*/
Return;
}




As you can see, in this allocation program, the release of memory uses a very simple mechanism to complete the release of memory within a fixed period of time. It is a little difficult to allocate memory. The following is a brief description of the algorithm:




Listing 5. pseudocode of the main allocation Program
1. If our Allocator has not been initialized, initialize it.
2. Add sizeof (struct mem_control_block) to the size requested.
3. Start at managed_memory_start.
4. Are we at last_valid address?
5. If we are:
A. We didn't find any existing space that was large enough
-- Ask the operating system for more and return that.
6. otherwise:
A. Is the current space available (check is_available from
The mem_control_block )?
B. If it is:
I) Is it large enough (check "size" from
Mem_control_block )?
Ii) if so:
A. Mark it as unavailable
B. Move past mem_control_block and return
Pointer
Iii) otherwise:
A. Move forward "size" bytes
B. Go back go step 4
C. otherwise:
I) Move Forward "size" bytes
Ii) Go Back To Step 4




We mainly use the connected pointer to traverse the memory to find open memory blocks. Here is the code:




Listing 6. Main allocation Program
Void * malloc (long numbytes ){
/* Holds where we are looking in memory */
Void * current_location;
/* This is the same as current_location, but cast to
* Memory_control_block
*/
Struct mem_control_block * current_location_mcb;
/* This is the memory location we will return. It will
* Be set to 0 until we find something suitable
*/
Void * memory_location;
/* Initialize if we haven't already done so */
If (! Has_initialized ){
Malloc_init ();
}
/* The memory we search for has to include the memory
* Control block, but the users of malloc don't need
* To know this, so we'll just add it in for them.
*/
Numbytes = numbytes + sizeof (struct mem_control_block );
/* Set memory_location to 0 until we find a suitable
* Location
*/
Memory_location = 0;
/* Begin searching at the start of managed memory */
Current_location = managed_memory_start;
/* Keep going until we have searched all allocated space */
While (current_location! = Last_valid_address)
{
/* Current_location and current_location_mcb point
* To the same address. However, current_location_mcb
* Is of the correct type, so we can use it as a struct.
* Current_location is a void pointer so we can use it
* To calculate addresses.
*/
Current_location_mcb =
(Struct mem_control_block *) current_location;
If (current_location_mcb-> is_available)
{
If (current_location_mcb-> size> = numbytes)
{
/* Woohoo! We 've found an open,
* Appropriately-size location.
*/
/* It is no longer available */
Current_location_mcb-> is_available = 0;
/* We own it */
Memory_location = current_location;
/* Leave the loop */
Break;
}
}
/* If we made it here, it's because the current Memory
* Block not suitable; move to the next one
*/
Current_location = current_location +
Current_location_mcb-> size;
}
/* If we still don't have a valid location, we'll
* Have to ask the operating system for more memory
*/
If (! Memory_location)
{
/* Move the program break numbytes further */
Sbrk (numbytes );
/* The new memory will be where the last valid
* Address left off
*/
Memory_location = last_valid_address;
/* We'll move the last valid address forward
* Numbytes
*/
Last_valid_address = last_valid_address + numbytes;
/* We Need to initialize the mem_control_block */
Current_location_mcb = memory_location;
Current_location_mcb-> is_available = 0;
Current_location_mcb-> size = numbytes;
}
/* Now, no matter what (well, cannot t for error conditions ),
* Memory_location has the address of the memory, including
* The mem_control_block
*/
/* Move the pointer past the mem_control_block */
Memory_location = memory_location + sizeof (struct mem_control_block );
/* Return the pointer */
Return memory_location;
}




This is our memory manager. Now, we only need to build it and use it in the program.
 


5. Other implementations of malloc ()


There are many implementations of malloc (), which have their own advantages and disadvantages. When designing a allocation program, you must have a number of compromise options, including:


The allocation speed.
Recovery speed.
Behaviors in a threaded environment.
Memory usage.
Local cache.
Bookkeeping memory overhead.
Behaviors in the virtual memory environment.
Small or large objects.
Real-time assurance.
Each implementation has its own set of advantages and disadvantages. In our simple allocation program, the allocation is very slow, and the collection is very fast. In addition, because it is poor in using the virtual memory system, it is most suitable for processing large objects.


There are many other allocation programs available. Including:


Doug Lea malloc: Doug Lea malloc is actually a complete set of allocation programs, including Doug Lea's original allocation program, GNU libc allocation program, and ptmalloc. Doug Lea's allocation program has a basic structure similar to our version, but it adds an index, which makes the search faster, in addition, multiple unused blocks can be combined into a large block. It also supports caching to reuse recently released memory more quickly. Ptmalloc is an extension of Doug Lea malloc and supports multithreading. In the reference section after this article, there is an article describing Doug Lea's malloc implementation.




BSD malloc: BSD malloc is implemented along with the release of 4.2 BSD and is included in FreeBSD. This allocation program can allocate objects from the pool consisting of objects of a predetermined size. It has some size classes used for object size. These objects are several power values of 2 minus a constant. Therefore, if you request an object of a given size, it will simply allocate a size class that matches it. This provides a quick implementation, but may waste memory. In the reference section, there is an article describing the implementation.




Hoard: the goal of hoard writing is to make the memory allocation very fast in a multi-threaded environment. Therefore, its construction is centered on the use of locks, so that all processes do not have to wait for memory allocation. It can significantly speed up the multi-threaded processes that perform a lot of allocation and recovery. In the reference section, there is an article describing the implementation.
The most famous among the many available allocation programs is the aforementioned allocation programs. If your program has special allocation requirements, you may be more willing to write a customized allocation program that matches your program's memory allocation method. However, if you are not familiar with the design of the Assignment Program, the custom Assignment Program will usually cause more problems than they solve.


6. Conclusion


As mentioned above, after calling malloc () multiple times, the idle memory is cut into many small memory segments, which enables the user to apply for memory usage, because the memory space cannot be found, malloc () requires memory sorting, making the function performance lower and lower. Smart programmers can minimize potential malloc performance loss by allocating memory blocks with a power of 2. In other words, the size of the allocated memory block is 4 bytes, 8 bytes, 16 bytes, 18446744073709551616 bytes, and so on. This minimizes the number of weird fragments that enter the idle chain (all small fragments in various sizes. Although it seems to be a waste of space, it is easy to see that the waste of space will never exceed 50%.


References:


[1] Jonathan Bartlett, memory management insider. developerworks, China, September November 2004


[2] Jan lindbglad, memory fragment processing technology. edn electronic design technology, October 08, 2004

Several implementation methods of malloc ()

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.