有谁知道malloc和free的实现机制,有源代码吗?

superspring 2009-07-14 07:28:08
谢谢
...全文
976 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
kangnixi 2010-02-17
  • 打赏
  • 举报
回复
mark一下,以备后用
suchx 2009-07-16
  • 打赏
  • 举报
回复
CSAPP P627介绍动态存储器分配的那一部分有很详细的介绍,希望楼主认真看
易之阴阳 2009-07-15
  • 打赏
  • 举报
回复

头文件mm.h
#ifndef _MM_H
#define _MM_H

#define PAGE_SIZE 4096

extern unsigned long get_free_page(void);
extern unsigned long put_page(unsigned long page,unsigned long address);
extern void free_page(unsigned long addr);

#endif

头文件system.h
#define move_to_user_mode() \
__asm__ ("movl %%esp,%%eax\n\t" \
"pushl $0x17\n\t" \
"pushl %%eax\n\t" \
"pushfl\n\t" \
"pushl $0x0f\n\t" \
"pushl $1f\n\t" \
"iret\n" \
"1:\tmovl $0x17,%%eax\n\t" \
"movw %%ax,%%ds\n\t" \
"movw %%ax,%%es\n\t" \
"movw %%ax,%%fs\n\t" \
"movw %%ax,%%gs" \
:::"ax")

#define sti() __asm__ ("sti"::)
#define cli() __asm__ ("cli"::)
#define nop() __asm__ ("nop"::)

#define iret() __asm__ ("iret"::)

#define _set_gate(gate_addr,type,dpl,addr) \
__asm__ ("movw %%dx,%%ax\n\t" \
"movw %0,%%dx\n\t" \
"movl %%eax,%1\n\t" \
"movl %%edx,%2" \
: \
: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
"o" (*((char *) (gate_addr))), \
"o" (*(4+(char *) (gate_addr))), \
"d" ((char *) (addr)),"a" (0x00080000))

#define set_intr_gate(n,addr) \
_set_gate(&idt[n],14,0,addr)

#define set_trap_gate(n,addr) \
_set_gate(&idt[n],15,0,addr)

#define set_system_gate(n,addr) \
_set_gate(&idt[n],15,3,addr)

#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\
*(gate_addr) = ((base) & 0xff000000) | \
(((base) & 0x00ff0000)>>16) | \
((limit) & 0xf0000) | \
((dpl)<<13) | \
(0x00408000) | \
((type)<<8); \
*((gate_addr)+1) = (((base) & 0x0000ffff)<<16) | \
((limit) & 0x0ffff); }

#define _set_tssldt_desc(n,addr,type) \
__asm__ ("movw $104,%1\n\t" \
"movw %%ax,%2\n\t" \
"rorl $16,%%eax\n\t" \
"movb %%al,%3\n\t" \
"movb $" type ",%4\n\t" \
"movb $0x00,%5\n\t" \
"movb %%ah,%6\n\t" \
"rorl $16,%%eax" \
::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
"m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
)

#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x89")
#define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x82")
易之阴阳 2009-07-15
  • 打赏
  • 举报
回复
最近在研究LINUX 0.11
供你参考
/*
* malloc.c --- a general purpose kernel memory allocator for Linux.
*
* Written by Theodore Ts'o (tytso@mit.edu), 11/29/91
*
* This routine is written to be as fast as possible, so that it
* can be called from the interrupt level.
*
* Limitations: maximum size of memory we can allocate using this routine
* is 4k, the size of a page in Linux.
*
* The general game plan is that each page (called a bucket) will only hold
* objects of a given size. When all of the object on a page are released,
* the page can be returned to the general free pool. When malloc() is
* called, it looks for the smallest bucket size which will fulfill its
* request, and allocate a piece of memory from that bucket pool.
*
* Each bucket has as its control block a bucket descriptor which keeps
* track of how many objects are in use on that page, and the free list
* for that page. Like the buckets themselves, bucket descriptors are
* stored on pages requested from get_free_page(). However, unlike buckets,
* pages devoted to bucket descriptor pages are never released back to the
* system. Fortunately, a system should probably only need 1 or 2 bucket
* descriptor pages, since a page can hold 256 bucket descriptors (which
* corresponds to 1 megabyte worth of bucket pages.) If the kernel is using
* that much allocated memory, it's probably doing something wrong. :-)
*
* Note: malloc() and free() both call get_free_page() and free_page()
* in sections of code where interrupts are turned off, to allow
* malloc() and free() to be safely called from an interrupt routine.
* (We will probably need this functionality when networking code,
* particularily things like NFS, is added to Linux.) However, this
* presumes that get_free_page() and free_page() are interrupt-level
* safe, which they may not be once paging is added. If this is the
* case, we will need to modify malloc() to keep a few unused pages
* "pre-allocated" so that it can safely draw upon those pages if
* it is called from an interrupt routine.
*
* Another concern is that get_free_page() should not sleep; if it
* does, the code is carefully ordered so as to avoid any race
* conditions. The catch is that if malloc() is called re-entrantly,
* there is a chance that unecessary pages will be grabbed from the
* system. Except for the pages for the bucket descriptor page, the
* extra pages will eventually get released back to the system, though,
* so it isn't all that bad.
*/

#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/system.h>

struct bucket_desc { /* 16 bytes */
void *page;
struct bucket_desc *next;
void *freeptr;
unsigned short refcnt;
unsigned short bucket_size;
};

struct _bucket_dir { /* 8 bytes */
int size;
struct bucket_desc *chain;
};

/*
* The following is the where we store a pointer to the first bucket
* descriptor for a given size.
*
* If it turns out that the Linux kernel allocates a lot of objects of a
* specific size, then we may want to add that specific size to this list,
* since that will allow the memory to be allocated more efficiently.
* However, since an entire page must be dedicated to each specific size
* on this list, some amount of temperance must be exercised here.
*
* Note that this list *must* be kept in order.
*/
struct _bucket_dir bucket_dir[] = {
{ 16, (struct bucket_desc *) 0},
{ 32, (struct bucket_desc *) 0},
{ 64, (struct bucket_desc *) 0},
{ 128, (struct bucket_desc *) 0},
{ 256, (struct bucket_desc *) 0},
{ 512, (struct bucket_desc *) 0},
{ 1024, (struct bucket_desc *) 0},
{ 2048, (struct bucket_desc *) 0},
{ 4096, (struct bucket_desc *) 0},
{ 0, (struct bucket_desc *) 0}}; /* End of list marker */

/*
* This contains a linked list of free bucket descriptor blocks
*/
struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0;

/*
* This routine initializes a bucket description page.
*/
static inline void init_bucket_desc()
{
struct bucket_desc *bdesc, *first;
int i;

first = bdesc = (struct bucket_desc *) get_free_page();
if (!bdesc)
panic("Out of memory in init_bucket_desc()");
for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) {
bdesc->next = bdesc+1;
bdesc++;
}
/*
* This is done last, to avoid race conditions in case
* get_free_page() sleeps and this routine gets called again....
*/
bdesc->next = free_bucket_desc;
free_bucket_desc = first;
}

void *malloc(unsigned int len)
{
struct _bucket_dir *bdir;
struct bucket_desc *bdesc;
void *retval;

/*
* First we search the bucket_dir to find the right bucket change
* for this request.
*/
for (bdir = bucket_dir; bdir->size; bdir++)
if (bdir->size >= len)
break;
if (!bdir->size) {
printk("malloc called with impossibly large argument (%d)\n",
len);
panic("malloc: bad arg");
}
/*
* Now we search for a bucket descriptor which has free space
*/
cli(); /* Avoid race conditions */
for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next)
if (bdesc->freeptr)
break;
/*
* If we didn't find a bucket with free space, then we'll
* allocate a new one.
*/
if (!bdesc) {
char *cp;
int i;

if (!free_bucket_desc)
init_bucket_desc();
bdesc = free_bucket_desc;
free_bucket_desc = bdesc->next;
bdesc->refcnt = 0;
bdesc->bucket_size = bdir->size;
bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();
if (!cp)
panic("Out of memory in kernel malloc()");
/* Set up the chain of free objects */
for (i=PAGE_SIZE/bdir->size; i > 1; i--) {
*((char **) cp) = cp + bdir->size;
cp += bdir->size;
}
*((char **) cp) = 0;
bdesc->next = bdir->chain; /* OK, link it in! */
bdir->chain = bdesc;
}
retval = (void *) bdesc->freeptr;
bdesc->freeptr = *((void **) retval);
bdesc->refcnt++;
sti(); /* OK, we're safe again */
return(retval);
}

/*
* Here is the free routine. If you know the size of the object that you
* are freeing, then free_s() will use that information to speed up the
* search for the bucket descriptor.
*
* We will #define a macro so that "free(x)" is becomes "free_s(x, 0)"
*/
void free_s(void *obj, int size)
{
void *page;
struct _bucket_dir *bdir;
struct bucket_desc *bdesc, *prev;

/* Calculate what page this object lives in */
page = (void *) ((unsigned long) obj & 0xfffff000);
/* Now search the buckets looking for that page */
for (bdir = bucket_dir; bdir->size; bdir++) {
prev = 0;
/* If size is zero then this conditional is always false */
if (bdir->size < size)
continue;
for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) {
if (bdesc->page == page)
goto found;
prev = bdesc;
}
}
panic("Bad address passed to kernel free_s()");
found:
cli(); /* To avoid race conditions */
*((void **)obj) = bdesc->freeptr;
bdesc->freeptr = obj;
bdesc->refcnt--;
if (bdesc->refcnt == 0) {
/*
* We need to make sure that prev is still accurate. It
* may not be, if someone rudely interrupted us....
*/
if ((prev && (prev->next != bdesc)) ||
(!prev && (bdir->chain != bdesc)))
for (prev = bdir->chain; prev; prev = prev->next)
if (prev->next == bdesc)
break;
if (prev)
prev->next = bdesc->next;
else {
if (bdir->chain != bdesc)
panic("malloc bucket chains corrupted");
bdir->chain = bdesc->next;
}
free_page((unsigned long) bdesc->page);
bdesc->next = free_bucket_desc;
free_bucket_desc = bdesc;
}
sti();
return;
}
下面是头文件
/*
* 'kernel.h' contains some often-used function prototypes etc
*/
void verify_area(void * addr,int count);
volatile void panic(const char * str);
int printf(const char * fmt, ...);
int printk(const char * fmt, ...);
int tty_write(unsigned ch,char * buf,int count);
void * malloc(unsigned int size);
void free_s(void * obj, int size);

#define free(x) free_s((x), 0)

/*
* This is defined as a macro, but at some point this might become a
* real subroutine that sets a flag if it returns true (to do
* BSD-style accounting where the process is flagged if it uses root
* privs). The implication of this is that you should do normal
* permissions checks first, and check suser() last.
*/
#define suser() (current->euid == 0)



cheng_fengming 2009-07-15
  • 打赏
  • 举报
回复
有这么麻烦吗?就是把malloc()和free()函数的原型写出来就可以了吧?

#define NULL 0
#define ALLOCSIZE 1000
char allocbuf[ALLOCSIZE];
char *allocp = allocbuf;

char *alloc(int n)
{
if (allocp+n <= allocbuf + ALLOCSIZE)
{
allocp += n;
return(allocp - n); //返回一个指针,它指向存区的开始位置
}
else
{
return (NULL); //当存区不够分配时,返回一个空指针
}
}

free(char *p)
{
if (p >=allocbuf && p < allocbuf + ALLOCSIZE)
{
allocp = p;
}
}
lbh2001 2009-07-15
  • 打赏
  • 举报
回复
/***
*malloc.c - Get a block of memory from the heap
*
* Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* Defines the malloc() function.
*
*******************************************************************************/

#include <cruntime.h>
#include <malloc.h>
#include <internal.h>
#include <mtdll.h>
#include <dbgint.h>

#ifdef WINHEAP
#include <windows.h>
#include <winheap.h>
#else /* WINHEAP */
#include <heap.h>
#endif /* WINHEAP */


extern int _newmode; /* malloc new() handler mode */


/***
*void *malloc(size_t size) - Get a block of memory from the heap
*
*Purpose:
* Allocate of block of memory of at least size bytes from the heap and
* return a pointer to it.
*
* Calls the new appropriate new handler (if installed).
*
*Entry:
* size_t size - size of block requested
*
*Exit:
* Success: Pointer to memory block
* Failure: NULL (or some error value)
*
*Uses:
*
*Exceptions:
*
*******************************************************************************/

void * __cdecl _malloc_base (size_t size)

{
return _nh_malloc_base(size, _newmode);
}


/***
*void *_nh_malloc_base(size_t size) - Get a block of memory from the heap
*
*Purpose:
* Allocate of block of memory of at least size bytes from the heap and
* return a pointer to it.
*
* Calls the appropriate new handler (if installed).
*
* There are two distinct new handler schemes supported. The 'new' ANSI
* C++ scheme overrides the 'old' scheme when it is activated. A value of
* _NOPTH for the 'new' handler indicates that it is inactivated and the
* 'old' handler is then called.
*
*Entry:
* size_t size - size of block requested
*
*Exit:
* Success: Pointer to memory block
* Failure: NULL (or some error value)
*
*Uses:
*
*Exceptions:
*
*******************************************************************************/

void * __cdecl _nh_malloc_base (size_t size, int nhFlag)
{
void * pvReturn;

// validate size
if (size > _HEAP_MAXREQ)
return NULL;

#ifndef WINHEAP
/* round requested size */
size = _ROUND2(size, _GRANULARITY);
#endif /* WINHEAP */

for (;;) {

// allocate memory block
if (size <= _HEAP_MAXREQ)
pvReturn = _heap_alloc_base(size);
else
pvReturn = NULL;

// if successful allocation, return pointer to memory
// if new handling turned off altogether, return NULL

if (pvReturn || nhFlag == 0)
return pvReturn;

// call installed new handler
if (!_callnewh(size))
return NULL;

// new handler was successful -- try to allocate again
}
}

/***
*void *_heap_alloc_base(size_t size) - does actual allocation
*
*Purpose:
* Same as malloc() except the new handler is not called.
*
*Entry:
* See malloc
*
*Exit:
* See malloc
*
*Exceptions:
*
*******************************************************************************/

void * __cdecl _heap_alloc_base (size_t size)

{
#ifdef WINHEAP
void * pvReturn;
#else /* WINHEAP */
_PBLKDESC pdesc;
_PBLKDESC pdesc2;
#endif /* WINHEAP */


#ifdef WINHEAP

if (size <= __sbh_threshold)
{
_mlock(_HEAP_LOCK);
pvReturn = __sbh_alloc_block(size);
_munlock(_HEAP_LOCK);
if (pvReturn)
return pvReturn;
}

if (size == 0)
size = 1;
size = (size + BYTES_PER_PARA - 1) & ~(BYTES_PER_PARA - 1);
return HeapAlloc(_crtheap, 0, size);
}

#else /* WINHEAP */

/* try to find a big enough free block
*/
if ( (pdesc = _heap_search(size)) == NULL )
{
if ( _heap_grow(size) != -1 )
{
/* try finding a big enough free block again. the
* success of the call to _heap_grow should guarantee
* it, but...
*/
if ( (pdesc = _heap_search(size)) == NULL )
{
/* something unexpected, and very bad, has
* happened. abort!
*/
_heap_abort();
}
}
else
return NULL;
}

/* carve the block into two pieces (if necessary). the first piece
* shall be of the exact requested size, marked inuse and returned to
* the caller. the leftover piece is to be marked free.
*/
if ( _BLKSIZE(pdesc) != size ) {
/* split up the block and free the leftover piece back to
* the heap
*/
if ( (pdesc2 = _heap_split_block(pdesc, size)) != NULL )
_SET_FREE(pdesc2);
}

/* mark pdesc inuse
*/
_SET_INUSE(pdesc);

/* check proverdesc and reset, if necessary
*/

_heap_desc.proverdesc = pdesc->pnextdesc;

return( (void *)((char *)_ADDRESS(pdesc) + _HDRSIZE) );
}


/***
*_PBLKDESC _heap_split_block(pdesc, newsize) - split a heap allocation block
* into two allocation blocks
*
*Purpose:
* Split the allocation block described by pdesc into two blocks, the
* first one being of newsize bytes.
*
* Notes: It is caller's responsibilty to set the status (i.e., free
* or inuse) of the two new blocks, and to check and reset proverdesc
* if necessary. See Exceptions (below) for additional requirements.
*
*Entry:
* _PBLKDESC pdesc - pointer to the allocation block descriptor
* size_t newsize - size for the first of the two sub-blocks (i.e.,
* (i.e., newsize == _BLKSIZE(pdesc), on exit)
*
*Exit:
* If successful, return a pointer to the descriptor for the leftover
* block.
* Otherwise, return NULL.
*
*Exceptions:
* It is assumed pdesc points to a valid allocation block descriptor and
* newsize is a valid heap block size as is (i.e., WITHOUT rounding). If
* either of these of assumption is violated, _heap_split_block() will
* likely corrupt the heap. Note also that _heap_split_block will simply
* return to the caller if newsize >= _BLKSIZE(pdesc), on entry.
*
*******************************************************************************/

_PBLKDESC __cdecl _heap_split_block (
REG1 _PBLKDESC pdesc,
size_t newsize
)
{
REG2 _PBLKDESC pdesc2;

_ASSERTE(("_heap_split_block: bad pdesc arg", _CHECK_PDESC(pdesc)));
_ASSERTE(("_heap_split_block: bad newsize arg", _ROUND2(newsize,_GRANULARITY) == newsize));

/* carve the block into two pieces (if possible). the first piece
* is to be exactly newsize bytes.
*/
if ( (_BLKSIZE(pdesc) > newsize) && ((pdesc2 = __getempty())
!= NULL) )
{
/* set it up to manage the second piece and link it in to
* the list
*/
pdesc2->pblock = (void *)((char *)_ADDRESS(pdesc) + newsize +
_HDRSIZE);
*(void **)(pdesc2->pblock) = pdesc2;
pdesc2->pnextdesc = pdesc->pnextdesc;
pdesc->pnextdesc = pdesc2;

return pdesc2;
}
return NULL;
}

#endif /* WINHEAP */

jinzonghui 2009-07-15
  • 打赏
  • 举报
回复
学习。
akcw007 2009-07-15
  • 打赏
  • 举报
回复
依赖平台
海枫 2009-07-14
  • 打赏
  • 举报
回复
http://g.oswego.edu/dl/html/malloc.html

一个外国高手写的文章,非常适合你的要求。
独孤过儿 2009-07-14
  • 打赏
  • 举报
回复
malloc()和free()虽然是在标准C的函数库里面,但是实际的工作是通过系统调用来实现的

可以看minix或者linux的源码
Wolf0403 2009-07-14
  • 打赏
  • 举报
回复
TCPL 应该是第八(?)章,Unix 系统界面 里面有。
liao05050075 2009-07-14
  • 打赏
  • 举报
回复
http://baike.baidu.com/view/736228.htm
Nio96 2009-07-14
  • 打赏
  • 举报
回复
malloc的源码:

http://topic.csdn.net/u/20081107/17/a0e8e8d0-1b30-459e-a640-53966f3e7640.html

free的源代码:

struct mem_control_block {
int is_available; //这是一个标记
int size; //这是实际空间的大小
}

void free(void *ptr)
{
struct mem_control_block *free;
free = ptr - sizeof(struct mem_control_block);
free->is_available = 1;
return;
}
xiongzhijian 2009-07-14
  • 打赏
  • 举报
回复
up
lzy0001sl 2009-07-14
  • 打赏
  • 举报
回复
在C标准库函数中有这两个函数的源代码,我看过,由于代码太多1400行,我看不明白。如果楼主有毅力就看吧!标准库函数在CSDN的下载频道可以搜到!
pysjp 2009-07-14
  • 打赏
  • 举报
回复
GCC编译器中的libC目录中有,是提供了源码的,不过那只是Unix/Linux的实现,Windows估计不一样
JoyerHuang_悦 2009-07-14
  • 打赏
  • 举报
回复
无论是VC的CRT,还是GCC用的libc,malloc和free的源代码都是提供的,
但是你没有相关算法基础,查看起来也只是头痛。

我手头有本《Unix Internals 3rd》,其中的两章Memory相关算法讲得很
细,包括用户态的malloc实现,以及内核态下的brk或者VritualAlloc都
有描述。
luc_cj 2009-07-14
  • 打赏
  • 举报
回复
LZ得学习学习内存管理机制了。。。
ies_sweet 2009-07-14
  • 打赏
  • 举报
回复
malloc/free 是操作系统提供的接口
不同的系统可能使用不同的库
接口形式相同,但是实现方式可能不同
这主要取决于操作系统内存管理模式

一般来说
系统会维持一个全局的表,来表示那些内存是空闲,哪些已分配
当操作这个表时,需要获取互斥锁

这也是为什么不能在ISR中使用malloc的原因

具体的楼主可以搜索内存管理的内容来学习。
大前置 2009-07-14
  • 打赏
  • 举报
回复
http://topic.csdn.net/u/20090714/07/f7ddd06a-917b-42d0-9c99-ac4deac08904.html?21758
加载更多回复(1)

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧