RT-Thread学习2 —— 内存管理学习记录
RT-Thread学习2 —— 内存管理学习记录1
小内存管理算法(mem.c)
1. 小内存管理法:
小内存管理算法是一个简单的内存分配算法。初始时,它是一块大的内存。当需要分配内存块时,将从这个大的内存块上分割出相匹配的内存块,然后把分割出来的空闲内存块还回给堆管理系统中。每个内存块都包含一个管理用的数据头,通过这个头把使用块与空闲块用双向链表的方式链接起来,如下图所示:
2. 两大数据结构体
rt_samll_mem:记录整个内存对象的基本信息
rt_samll_mem_item:记录各个内存块的使用情况
3. 初始化函数:rt_smem_init
在函数参数合法的情况下执行后的初始化内存结构大致如下图所示:
4. rt_smem_alloc函数和rt_smem_realloc函数
/**
* @brief Allocate a block of memory with a minimum of 'size' bytes.
*
* @param m the small memory management object.
*
* @param size is the minimum size of the requested block in bytes.
*
* @return the pointer to allocated memory or NULL if no free memory was found.
*/
void *rt_smem_alloc(rt_smem_t m, rt_size_t size)
{
rt_size_t ptr, ptr2;
struct rt_small_mem_item *mem, *mem2;
struct rt_small_mem *small_mem;
if (size == 0)
return RT_NULL;
RT_ASSERT(m != RT_NULL);
RT_ASSERT(rt_object_get_type(&m->parent) == RT_Object_Class_Memory);
RT_ASSERT(rt_object_is_systemobject(&m->parent));
if (size != RT_ALIGN(size, RT_ALIGN_SIZE))
RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d, but align to %d\n",
size, RT_ALIGN(size, RT_ALIGN_SIZE)));
else
RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d\n", size));
small_mem = (struct rt_small_mem *)m;
/* alignment size */
size = RT_ALIGN(size, RT_ALIGN_SIZE);
//判断申请的空间是不是大于整个内存的空间
if (size > small_mem->mem_size_aligned)
{
RT_DEBUG_LOG(RT_DEBUG_MEM, ("no memory\n"));
return RT_NULL;
}
//确保申请的空间最小是对齐size的大小
/* every data block must be at least MIN_SIZE_ALIGNED long */
if (size < MIN_SIZE_ALIGNED)
size = MIN_SIZE_ALIGNED;
//遍历每一个item
for (ptr = (rt_uint8_t *)small_mem->lfree - small_mem->heap_ptr;
ptr <= small_mem->mem_size_aligned - size;
ptr = ((struct rt_small_mem_item *)&small_mem->heap_ptr[ptr])->next)
{
mem = (struct rt_small_mem_item *)&small_mem->heap_ptr[ptr];
//找空闲块并且这个空闲块的大小比要申请的大的块
if ((!MEM_ISUSED(mem)) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size)
{
/* mem is not used and at least perfect fit is possible:
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
//如果当前的item后面跟的内存块比要申请的空间加其他描述信息的空间大,那就符合条件
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >=
(size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED))
{
/* (in addition to the above, we test if another struct rt_small_mem_item (SIZEOF_STRUCT_MEM) containing
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
* -> split large block, create empty remainder,
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
* struct rt_small_mem_item would fit in but no data between mem2 and mem2->next
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
* region that couldn't hold data, but when mem->next gets freed,
* the 2 regions would be combined, resulting in more free memory
*/
//ptr2 指向当前信息块加实际内存块后的地址(下一个空闲块要写入对应的信息块)
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
//mem2为下一个信息块赋值
/* create mem2 struct */
mem2 = (struct rt_small_mem_item *)&small_mem->heap_ptr[ptr2];
mem2->pool_ptr = MEM_FREED();
mem2->next = mem->next;
mem2->prev = ptr;
#ifdef RT_USING_MEMTRACE
rt_smem_setname(mem2, " ");
#endif /* RT_USING_MEMTRACE */
//设置当前信息块的下一个为pt2
/* and insert it between mem and mem->next */
mem->next = ptr2;
//如果不是初始时候的第一块那需要把end of heap的pre指向ptr2
if (mem2->next != small_mem->mem_size_aligned + SIZEOF_STRUCT_MEM)
{
((struct rt_small_mem_item *)&small_mem->heap_ptr[mem2->next])->prev = ptr2;
}
small_mem->parent.used += (size + SIZEOF_STRUCT_MEM);
if (small_mem->parent.max < small_mem->parent.used)
small_mem->parent.max = small_mem->parent.used;
}
else
{
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
* take care of this).
* -> near fit or excact fit: do not split, no mem2 creation
* also can't move mem->next directly behind mem, since mem->next
* will always be used at this point!
*/
//如果不够长,将位置占上
small_mem->parent.used += mem->next - ((rt_uint8_t *)mem - small_mem->heap_ptr);
if (small_mem->parent.max < small_mem->parent.used)
small_mem->parent.max = small_mem->parent.used;
}
//设置当前要申请的内存的信息块
/* set small memory object */
mem->pool_ptr = MEM_USED();
#ifdef RT_USING_MEMTRACE
if (rt_thread_self())
rt_smem_setname(mem, rt_thread_self()->name);
else
rt_smem_setname(mem, "NONE");
#endif /* RT_USING_MEMTRACE */
//将lfree指向下一个空闲的位置
if (mem == small_mem->lfree)
{
/* Find next free block after mem and update lowest free pointer */
while (MEM_ISUSED(small_mem->lfree) && small_mem->lfree != small_mem->heap_end)
small_mem->lfree = (struct rt_small_mem_item *)&small_mem->heap_ptr[small_mem->lfree->next];
RT_ASSERT(((small_mem->lfree == small_mem->heap_end) || (!MEM_ISUSED(small_mem->lfree))));
}
RT_ASSERT((rt_ubase_t)mem + SIZEOF_STRUCT_MEM + size <= (rt_ubase_t)small_mem->heap_end);
RT_ASSERT((rt_ubase_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM) % RT_ALIGN_SIZE == 0);
RT_ASSERT((((rt_ubase_t)mem) & (RT_ALIGN_SIZE - 1)) == 0);
RT_DEBUG_LOG(RT_DEBUG_MEM,
("allocate memory at 0x%x, size: %d\n",
(rt_ubase_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM),
(rt_ubase_t)(mem->next - ((rt_uint8_t *)mem - small_mem->heap_ptr))));
//返回的是真实可以操作数据的地址(前面会又一个信息头)
/* return the memory data except mem struct */
return (rt_uint8_t *)mem + SIZEOF_STRUCT_MEM;
}
}
return RT_NULL;
}
/**
* @brief This function will change the size of previously allocated memory block.
*
* @param m the small memory management object.
*
* @param rmem is the pointer to memory allocated by rt_mem_alloc.
*
* @param newsize is the required new size.
*
* @return the changed memory block address.
*/
void *rt_smem_realloc(rt_smem_t m, void *rmem, rt_size_t newsize)
{
rt_size_t size;
rt_size_t ptr, ptr2;
struct rt_small_mem_item *mem, *mem2;
struct rt_small_mem *small_mem;
void *nmem;
RT_ASSERT(m != RT_NULL);
RT_ASSERT(rt_object_get_type(&m->parent) == RT_Object_Class_Memory);
RT_ASSERT(rt_object_is_systemobject(&m->parent));
small_mem = (struct rt_small_mem *)m;
/* alignment size */
newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
//新申请的比总空间大
if (newsize > small_mem->mem_size_aligned)
{
RT_DEBUG_LOG(RT_DEBUG_MEM, ("realloc: out of memory\n"));
return RT_NULL;
}
//新申请的大小是0
else if (newsize == 0)
{
rt_smem_free(rmem);
return RT_NULL;
}
//地址还没allocate
/* allocate a new memory block */
if (rmem == RT_NULL)
return rt_smem_alloc(&small_mem->parent, newsize);
RT_ASSERT((((rt_ubase_t)rmem) & (RT_ALIGN_SIZE - 1)) == 0);
RT_ASSERT((rt_uint8_t *)rmem >= (rt_uint8_t *)small_mem->heap_ptr);
RT_ASSERT((rt_uint8_t *)rmem < (rt_uint8_t *)small_mem->heap_end);
//取出申请内存的信息块
mem = (struct rt_small_mem_item *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM);
//计算当前信息块的大小
/* current memory block size */
ptr = (rt_uint8_t *)mem - small_mem->heap_ptr;
size = mem->next - ptr - SIZEOF_STRUCT_MEM;
if (size == newsize)
{
/* the size is the same as */
return rmem;
}
//当前信息块比新申请的大
if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size)
{
/* split memory block */
small_mem->parent.used -= (size - newsize);
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
mem2 = (struct rt_small_mem_item *)&small_mem->heap_ptr[ptr2];
mem2->pool_ptr = MEM_FREED();
mem2->next = mem->next;
mem2->prev = ptr;
#ifdef RT_USING_MEMTRACE
rt_smem_setname(mem2, " ");
#endif /* RT_USING_MEMTRACE */
mem->next = ptr2;
if (mem2->next != small_mem->mem_size_aligned + SIZEOF_STRUCT_MEM)
{
((struct rt_small_mem_item *)&small_mem->heap_ptr[mem2->next])->prev = ptr2;
}
if (mem2 < small_mem->lfree)
{
/* the splited struct is now the lowest */
small_mem->lfree = mem2;
}
plug_holes(small_mem, mem2);
return rmem;
}
/* expand memory */
nmem = rt_smem_alloc(&small_mem->parent, newsize);
if (nmem != RT_NULL) /* check memory */
{
rt_memcpy(nmem, rmem, size < newsize ? size : newsize);
rt_smem_free(rmem);
}
return nmem;
}
RTM_EXPORT(rt_smem_realloc);
RT-Thread学习2 —— 内存管理学习记录的更多相关文章
- java虚拟机学习-JVM内存管理:深入Java内存区域与OOM(3)
概述 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又 ...
- C++内存管理学习笔记(5)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- C++内存管理学习笔记(7)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- C++内存管理学习笔记(6)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...
- python学习Day9 内存管理
复习 :文件处理 1. 操作文件的三步骤:-- 打开文件:此时该文件在硬盘的空间被操作系统持有 | 文件对象被应用程序持用 -- 操作文件:读写操作 -- 释放文件:释放操作系统对文件在硬盘间的持有 ...
- Linux内存管理学习资料
下面是Linux内存管理学习的一些资料. 博客 mlock() and mlockall() system calls. All about Linux swap space 逆向映射的演进 Linu ...
- C++内存管理学习笔记(4)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- C++内存管理学习笔记(3)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
随机推荐
- 学习Java第4天
今天所作的工作: 1.类 2.类的构造方法 3.静态变量 4.类的主方法 5.对象 今天没有完成昨天的工作安排,因为发现进入类之后的编程思想发生的变化,相对与c++的逻辑既有较大的相似性又有不同的性质 ...
- WTM多租户改造
首先简单说下多租户的几种实现方式 多租户(Multi-Tenant ),即多个租户共用一个实例,租户的数据既有隔离又有共享,说到底是要解决数据存储的问题. 常用的数据存储方式有三种. 方案一:独立数据 ...
- eureka 集群的实现方式?
注意,本文还是对上一篇博客的延续,需要的配置,在前面的博客里面可以找到. eureka集群版 (正宗的eureka!) 2.1.配置eureka的集群之前首先先配置HOSTNAME和IP的映射 具体的 ...
- CKKS Part5: CKKS的重缩放
本文翻译于 CKKS EXPLAINED, PART 5: RESCALING,主要介绍CKKS方案中最重要的技术- rescaling,重缩放技术 介绍 在CKKS的前一篇文章 CKKS Part4 ...
- Atcoder ARC-104
D 可以发现,从整体上来看这个式子是不好计数的,可以考虑反过来将贡献拆到单个的每个数上: \[\sum\limits_{i = 1} ^ n a_i \times (i - x) = 0 \] 于是每 ...
- Redis集群安装详细步骤
环境: Centos7 redis3.0 三台虚拟机主机名分别为 master node1 node2 如果单机的时候设置过密码最好把密码去掉,避免位置的错误. 拍个快照方便恢复. 1.创 ...
- Class.getResource和ClassLoader.getResource的路径写法
Java中取资源时,经常用到Class.getResource和ClassLoader.getResource,这里来看看他们在取资源文件时候的路径问题. Class.getResource(Stri ...
- 手动加载nacos自定义配置到全局变量中
由于springboot启动顺序:先加载上下文再加载bean 开始日常搬砖: 1.通过启动日志发现nacos在PropertySourceBootstrapConfiguration中加载上下文配置: ...
- unittest基础篇1
转自http://blog.csdn.net/huilan_same/article/details/52944782 unittest是xUnit系列框架中的一员,如果你了解xUnit的其他成员,那 ...
- Linux基础入门笔记
今天带来Linux入门的一些基础的笔记,科班出身的同学们,Linux已经成为了必修课了,下面我带来关于Linux的相关入门知识以及Linux简单的介绍! Linux内核最初只是由芬兰人林纳斯·托瓦兹( ...