malloc 操作系统 C/C++ 自己实现

每个进程有自己独有的虚拟地址空间,此虚拟地址空间包括五部分:Text section(要由处理器执行的二进制指令)、BSS(包括初始化为0的静态数据等)、Heap(包括动态分配的数据)、Stack(包括自定义变量、函数参数等)

Heap由下(头部)向上(尾部)增长,程序中断指针或brk指针指向heap的尾部
如果想要在heap中分配更多的内存,需要向系统申请brk。

Sbrk系统调用可以操控program break:
Sbrk(0):提供程序中断的当前地址。
Sbrk(x):向系统申请x字节的内存
Sbrk(-x):释放x字节的内存给系统,出错返回(void*)-1

代码解读
1.当heap中没有满足条件的内存块时,可以通过sbrk(x)向系统申请内存放入heap;但是如果我们要释放heap末尾的内存块时(因为操作系统提供的堆内存是连续的。因此,我们只能释放堆末尾的内存。我们不能在操作系统的中间释放一块内存。),就会很麻烦,因为不知道要释放的内存块究竟多大。所以,我们可以为每个内存块添加一个信息头header结构体,包括:有效内存块大小、是否可用、一个header链表(指针指向下一个内存块的header部分的首地址)。并且header结构体放在一个union内,16字节对齐。

2.为了防止两个或多个线程同时访问内存,我们设置一个全局锁,在内存上的每一个操作之前,你必须获取锁,操作完成后,必须释放锁。

在这里插入图片描述

在这里插入图片描述
mymalloc.cpp

#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include "mymalloc.h"

// 将包含内存块头部信息的结构体放在union中,从而控制头部header所占空间的长度
union header {
	struct {
		size_t size;
		unsigned is_free;
		union header *next;
	} s;
	char Align[16];  // 控制长度
};
typedef union header header_t;

header_t *head = NULL, *tail = NULL;

// 为了防止两个或多个线程同时访问内存,设置一个全局锁
pthread_mutex_t global_malloc_lock;

/*
循环遍历链表,判断是否存在满足条件的内存块
返回值:
存在 返回内存块的有效内存部分的首地址
不存在 返回NULL
*/
header_t *get_free_block(size_t size)
{
	header_t *curr = head;
	while(curr) {
		if (curr->s.is_free && curr->s.size >= size)
			return curr;
		curr = curr->s.next;
	}
	return NULL;
}

/*
释放内存块
*/
void myfree(void *block)
{
	header_t *header, *tmp;
	
	// void指针可以指向任意类型的数据
	void *programbreak;

	if (!block)
		return;
	pthread_mutex_lock(&global_malloc_lock);
	// 将header指向 block(有效内存的首地址)所在内存块的头部
	header = (header_t*)block - 1;
	// sbrk(0)获取当前程序中断地址
	programbreak = sbrk(0);

	/* 判断要释放的内存块是否为heap的末尾内存块 */
	// 是,则将内存块释放给系统
	if ((char*)block + header->s.size == programbreak) {
		if (head == tail) {
			head = tail = NULL;
		} else {
			tmp = head;
			while (tmp) {
				if(tmp->s.next == tail) {
					tmp->s.next = NULL;
					tail = tmp;
				}
				tmp = tmp->s.next;
			}
		}
		sbrk(0 - header->s.size - sizeof(header_t));
		
		pthread_mutex_unlock(&global_malloc_lock);
		return;
	}
	// 否,则直接将该内存块的头部信息的s.is_free置为1,表示此内存快可被使用
	// 但并不释放给系统,还在进程的heap内
	header->s.is_free = 1;
	pthread_mutex_unlock(&global_malloc_lock);
}

/*
动态申请内存
*/
void *mymalloc(size_t size)
{
	size_t total_size;
	void *block;
	header_t *header;
	if (!size)
		return NULL;
	pthread_mutex_lock(&global_malloc_lock);
	header = get_free_block(size);
	
	if (header) {
		header->s.is_free = 0;
		pthread_mutex_unlock(&global_malloc_lock);
		return (void*)(header + 1);
	}
	
	total_size = sizeof(header_t) + size;
	// sbrk(x):向系统申请x字节的内存,出错返回(void*)-1
	block = sbrk(total_size);
	if (block == (void*) -1) {
		pthread_mutex_unlock(&global_malloc_lock);
		return NULL;
	}
	header = block;
	header->s.size = size;
	header->s.is_free = 0;
	header->s.next = NULL;
	// 如果head为空,说明此事heap为空,tail自然也为空;此时直接将head指向header首地址
	if (!head)
		head = header;
	// 如果tail不为空,则说明tail是heap末尾内存块的头部,此时应该将tail的s.next指向header首地址
	if (tail)
		tail->s.next = header;
	// 如果tail为空,则直接将tail指向header首地址
	tail = header;
	pthread_mutex_unlock(&global_malloc_lock);
	return (void*)(header + 1);
}

mymalloc .h

#ifndef MYMALLOC_H_INCLUDED
#define MYMALLOC_H_INCLUDED

void myfree(void *block);
void *mymalloc(size_t size);

#endif // MYMALLOC_H_INCLUDED

main

#include <stdio.h>
#include "mymalloc.h"

void main(int argc, char *argv[]){
  int *a;
  a = (int *) mymalloc(6 * sizeof(int ));
  a[3] = 9;
  printf("%d\n", a[3]);
  myfree(a);
  return ;
}

编译完成后在Linux shell命令行下打包执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值