堆内存管理算法的实现

头文件

/*
 * MemoryManage.h
 *
 *  Created on: 2020年2月22日
 *      Author: LuYonglei
 */

#ifndef SRC_MEMORYMANAGE_H_
#define SRC_MEMORYMANAGE_H_

#include <stdlib.h>
#include <stdint.h>
#include "task.h"

/*      字节对齐数  字节对齐掩码
 *         8        0x0007
 *         4        0x0003
 *         2        0x0001
 *         1        0x0000
 */
#define BYTE_ALIGNMENT 8           //字节对齐数
#define BYTE_ALIGNMENT_MASK 0x0007 //字节对齐掩码
#define TOTAL_HEAP_SIZE 1000       //堆大小
#define MIN_BLOCK_SIZE 32           //最小内存块大小
#define HEAP_BITS_PER_BYTE 8       //堆中每个字节拥有的位数

//定义内存控制块
typedef struct memory_control_block {
    struct memory_control_block *nextUsableBlock; //下一个空闲块的地址
    size_t blockSize; //空闲块的大小
} MCB;

void* los_malloc(size_t wantedSize); //动态分配一块内存,内存大小为 wantedSize Bytes
void los_free(void *addressToBeFree); //释放一块动态分配了的内存
size_t los_get_usable_heap_size(void); //获取当前未分配的内存堆大小
size_t los_get_ever_min_usable_heap_size(void); //获取未分配的内存堆的历史最小值
//以下函数为调试系统所用,实际使用中可删除
void OS_MemoryUsableInfo(void); //获取当前系统内存可分配情况

#endif /* SRC_MEMORYMANAGE_H_ */

源代码文件

/*
 * MemoryManage.c
 *
 *  Created on: 2020年2月22日
 *      Author: LuYonglei
 */
#include "MemoryManage.h"

static uint8_t Heap[TOTAL_HEAP_SIZE]; //编译器生成可用堆,堆的大小为TOTAL_HEAP_SIZE Bytes

static MCB heapStart; //堆的起始
static MCB *heapEnd; //堆的末尾
static size_t usableBytesRemaining; //当前剩余可用字节数
static size_t usableEverMinRemaining; //历史最小剩余可用字节数
static size_t adjustedHeapSize; //经过对齐调整后的堆的大小
static size_t blockAllocatedBit; //用一个位来标记内存块是否被分配

static size_t MCB_size = sizeof(MCB); //内存控制块大小
static void los_heap_init(void); //系统堆初始化函数,只在第一次动态分配内存时调用
static void los_insert_block_into_usable_list(MCB *toBeInsertedBlock); //把一块内存插入空闲内存链表

void* los_malloc(size_t wantedSize) {
    //动态分配一块内存,内存大小为 wantedSize Bytes
    MCB *currentBlock;
    MCB *previousBlock;
    MCB *newBlock;
    void *addressReturn = NULL;
    los_suspend_all_tasks(); //调度器锁打开
    {
        //如果是第一次分配内存就调用堆初始化函数
        if (heapEnd == NULL)
            los_heap_init();
        if (wantedSize > 0) {
            wantedSize += MCB_size;
            //如果需要进行内存对齐
            if ((wantedSize & BYTE_ALIGNMENT_MASK) != 0)
                wantedSize = (wantedSize + BYTE_ALIGNMENT)
                        & (~BYTE_ALIGNMENT_MASK);
        }
        //此处判断wantedSize是否超出限制
        if ((wantedSize & blockAllocatedBit) == 0) {
            //若没有超出限制
            if ((wantedSize > 0) && (wantedSize <= usableBytesRemaining)) {
                //如果申请的内存大小大于0,且系统剩余内存可以满足分配
                previousBlock = &heapStart;
                currentBlock = heapStart.nextUsableBlock;
                while ((currentBlock->blockSize < wantedSize)
                        && (currentBlock->nextUsableBlock != NULL)) {
                    previousBlock = currentBlock;
                    currentBlock = currentBlock->nextUsableBlock;
                }
                if (currentBlock != heapEnd) {
                    addressReturn =
                            (void*) ((size_t) (previousBlock->nextUsableBlock)
                                    + MCB_size);
                    //将当前空闲内存块从内存空闲链表移除
                    previousBlock->nextUsableBlock =
                            currentBlock->nextUsableBlock;
                    if ((currentBlock->blockSize - wantedSize) > MIN_BLOCK_SIZE) {
                        //如果这个内存块剩余的部分还可以再利用,就创建新的空闲内存块
                        newBlock = (MCB*) ((size_t) currentBlock + wantedSize);
                        //更新新的内存块的大小
                        newBlock->blockSize = currentBlock->blockSize
                                - wantedSize;
                        //改变原来的内存块的大小
                        currentBlock->blockSize = wantedSize;
                        //将新的空闲内存块插入到空闲内存块链表中去
                        los_insert_block_into_usable_list(newBlock);
                    }
                    //更新剩余内存总大小
                    usableBytesRemaining -= currentBlock->blockSize;
                    //如果当前剩余内存总大小小于历史剩余内存总大小的最小值,就更新历史值
                    if (usableBytesRemaining < usableEverMinRemaining)
                        usableEverMinRemaining = usableBytesRemaining;
                    //此处将内存块的最高位设置为1,标记内存块已经被申请使用
                    currentBlock->blockSize |= blockAllocatedBit;
                    currentBlock->nextUsableBlock = NULL;
                }
            }
        } else {
            //此处申请内存过大,超出size_t/2
        }
        //此处做trace操作
    }
    los_resume_all_tasks();    //调度器锁关闭
    return addressReturn;
}

void los_free(void *addressToBeFree) {
    uint8_t *baseAddressToBeFree = (uint8_t*) addressToBeFree;
    MCB *blockToBeFree;
    //判断释放的地址是否为空
    if (baseAddressToBeFree != NULL) {
        //经过偏移计算出内存控制块的基地址
        baseAddressToBeFree -= MCB_size;
        blockToBeFree = (MCB*) baseAddressToBeFree;
        //判断内存快是否已经被分配使用,如果是就是放内存块
        if ((blockToBeFree->blockSize & blockAllocatedBit) != 0) {
            if (blockToBeFree->nextUsableBlock == NULL) {
                //将内存块标识为空闲
                blockToBeFree->blockSize &= ~blockAllocatedBit;
                los_suspend_all_tasks();
                {
                    usableBytesRemaining += blockToBeFree->blockSize;
                    //此处做trace操作
                    los_insert_block_into_usable_list(blockToBeFree);
                }
                los_resume_all_tasks();
            }
        }
    }
}

static void los_heap_init(void) {
    //系统堆的初始化函数
    MCB *firstUsableBlock;
    uint8_t *alignedHeapBaseAddress;
    size_t totalHeapSize = TOTAL_HEAP_SIZE;
    //进行内存对齐操作
    size_t newHeapBaseAdress = (size_t) Heap; //获取堆数祖的地址
    if ((newHeapBaseAdress & BYTE_ALIGNMENT_MASK) != 0) {
        newHeapBaseAdress = (newHeapBaseAdress + BYTE_ALIGNMENT)
                & (~BYTE_ALIGNMENT_MASK);
        //内存对齐后,堆的大小发生变化
        totalHeapSize -= newHeapBaseAdress - (size_t) Heap;
    }
    alignedHeapBaseAddress = (uint8_t*) newHeapBaseAdress;
    //初始化空闲链表头部
    heapStart.nextUsableBlock = (MCB*) alignedHeapBaseAddress;
    heapStart.blockSize = (size_t) 0;
    //初始化链表尾部
    newHeapBaseAdress = ((size_t) alignedHeapBaseAddress) + totalHeapSize; //获取堆尾部地址
    newHeapBaseAdress -= MCB_size;
    newHeapBaseAdress &= ~((size_t) BYTE_ALIGNMENT_MASK); //完成heapEnd分配并进行内存对齐后的堆尾部地址
    //初始化链表尾部
    heapEnd = (MCB*) newHeapBaseAdress;
    heapEnd->nextUsableBlock = NULL;
    heapEnd->blockSize = (size_t) 0;
    //将当前所有内存插入空闲内存块链表
    firstUsableBlock = (MCB*) alignedHeapBaseAddress;
    firstUsableBlock->blockSize = newHeapBaseAdress - (size_t) firstUsableBlock;
    firstUsableBlock->nextUsableBlock = heapEnd;
    //更新统计变量
    adjustedHeapSize = firstUsableBlock->blockSize;    //内存对齐后系统管理的堆的大小
    usableEverMinRemaining = firstUsableBlock->blockSize;
    usableBytesRemaining = firstUsableBlock->blockSize;
    //内存块分配标志设置
    blockAllocatedBit = ((size_t) 1)
            << ((sizeof(size_t) * HEAP_BITS_PER_BYTE) - 1);
}

static void los_insert_block_into_usable_list(MCB *toBeInsertedBlock) {
    //把一块内存插入空闲内存链表
    MCB *blockIterator;
    uint8_t *tempAddress;
    //首先找到一个和toBeInsertedBlock相邻的前一个空闲内存
    blockIterator = &heapStart;
    while ((blockIterator->nextUsableBlock) < toBeInsertedBlock)
        blockIterator = blockIterator->nextUsableBlock;
    tempAddress = (uint8_t*) blockIterator;
    //如果前一个内存的尾部恰好是toBeInsertedBlock的头部,那么这两块空闲内存是连续的,可以合并
    if ((tempAddress + blockIterator->blockSize)
            == (uint8_t*) toBeInsertedBlock) {
        //将toBeInsertedBlock合并到blockIterator中
        blockIterator->blockSize += toBeInsertedBlock->blockSize;
        toBeInsertedBlock = blockIterator;
    }
    //判断是否和后面的空闲内存相邻
    tempAddress = (uint8_t*) toBeInsertedBlock;
    if ((tempAddress + toBeInsertedBlock->blockSize)
            == (uint8_t*) blockIterator->nextUsableBlock) {
        if (blockIterator->nextUsableBlock != heapEnd) {
            //如果后面的内存块的不是heapEnd
            //将后面的内存块合入toBeInsertedBlock
            toBeInsertedBlock->blockSize +=
                    blockIterator->nextUsableBlock->blockSize;
            toBeInsertedBlock->nextUsableBlock =
                    blockIterator->nextUsableBlock->nextUsableBlock;
        } else {
            //如果后面的内存块的是heapEnd,则只改变指针
            toBeInsertedBlock->nextUsableBlock = heapEnd;
        }
    } else {
        //如果和后面的内存块不相邻,就只能插入链表了
        toBeInsertedBlock->nextUsableBlock = blockIterator->nextUsableBlock;
    }
    //判断前面是否已经合并,如果没有合并就要更新链表
    if (toBeInsertedBlock != blockIterator) {
        blockIterator->nextUsableBlock = toBeInsertedBlock;
    }
}

size_t los_get_usable_heap_size(void) {
    return usableBytesRemaining;
}

size_t los_get_ever_min_usable_heap_size(void) {
    return usableEverMinRemaining;
}

void OS_MemoryUsableInfo(void) {
    MCB *start = &heapStart;
    MCB *end = heapEnd;
    start = start->nextUsableBlock;
    printf(
            "------------------------------------------------------------------\n");
    printf("当前可用内存大小为:%d\n", usableBytesRemaining);
    printf("历史最小可用大小:%d\n", usableEverMinRemaining);
    while (start != end) {
        printf("空闲内存块地址:%p ,空闲内存块大小 %d ,空闲内存块结束地址:%p\n", (size_t) start,
                start->blockSize, ((size_t) start) + start->blockSize);
        start = start->nextUsableBlock;
    }
    printf(
            "------------------------------------------------------------------\n");
}

 

posted @ 2020-03-02 17:50  路璐  阅读(442)  评论(0编辑  收藏  举报