内存池简单案例

        本章借助nginx源码中实现的内存池模块,将其抽离出来并实现一个简单的demo用于比较说明内存池的优点。内存池结构详细说明请见另一篇博文Nginx学习之内存管理

        首先,将nginx源码中ngx_palloc.h、ngx_palloc.c、ngx_alloc.h、ngx_alloc.c四个文件拷贝出来,对其做一下简单修改,使其不再依赖nginx项目源码。

        ngx_alloc.h具体代码如下:

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */

#ifndef _NGX_ALLOC_H_INCLUDED_
#define _NGX_ALLOC_H_INCLUDED_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <inttypes.h>

#ifndef u_char
#define u_char	unsigned char
#endif

#ifndef ngx_uint_t
#define	ngx_uint_t	 unsigned int
#endif

#ifndef ngx_int_t
#define ngx_int_t	int
#endif

#ifndef ngx_inline
#define ngx_inline      inline
#endif

void *ngx_alloc(size_t size, void *log);
void *ngx_calloc(size_t size, void *log);

#define ngx_free          free

#define ngx_memzero(buf, n)       (void) memset(buf, 0, n)
#define ngx_memset(buf, c, n)     (void) memset(buf, c, n)


/*
 * Linux has memalign() or posix_memalign()
 * Solaris has memalign()
 * FreeBSD 7.0 has posix_memalign(), besides, early version's malloc()
 * aligns allocations bigger than page size at the page boundary
 */

#if (NGX_HAVE_POSIX_MEMALIGN || NGX_HAVE_MEMALIGN)

void *ngx_memalign(size_t alignment, size_t size, void *log);

#else

#define ngx_memalign(alignment, size, log)  ngx_alloc(size, log)

#endif


extern ngx_uint_t  ngx_pagesize;
extern ngx_uint_t  ngx_pagesize_shift;
extern ngx_uint_t  ngx_cacheline_size;


#endif /* _NGX_ALLOC_H_INCLUDED_ */

        ngx_alloc.c具体代码如下:

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */

#include "ngx_alloc.h"

ngx_uint_t  ngx_pagesize;
ngx_uint_t  ngx_pagesize_shift;
ngx_uint_t  ngx_cacheline_size;

void *
ngx_alloc(size_t size, void *log)
{
    void  *p;

    p = malloc(size);
    if (p == NULL) {
		printf("----------malloc(%u) failed---------\n", size);
    }

	// printf("----------malloc: %p:%u---------\n", p, size);
    return p;
}


void *
ngx_calloc(size_t size, void *log)
{
    void  *p;

    p = ngx_alloc(size, log);

    if (p) {
        ngx_memzero(p, size);
    }

    return p;
}


#if (NGX_HAVE_POSIX_MEMALIGN)

void *
ngx_memalign(size_t alignment, size_t size, void *log)
{
    void  *p;
    int    err;

    err = posix_memalign(&p, alignment, size);

    if (err) {
		printf("----------posix_memalign(%u, %u) failed---------\n", alignment, size);
        p = NULL;
    }

	printf("----------posix_memalign: %p:%u @%u---------\n",  p, size, alignment);

    return p;
}

#elif (NGX_HAVE_MEMALIGN)

void *
ngx_memalign(size_t alignment, size_t size, void *log)
{
    void  *p;

    p = memalign(alignment, size);
    if (p == NULL) {
		printf("----------memalign(%u, %u) failed---------\n", alignment, size);
    }

	printf("----------memalign: %p:%u @%u---------\n",  p, size, alignment);

    return p;
}

#endif

        ngx_palloc.h具体代码如下:

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */

#ifndef _NGX_PALLOC_H_INCLUDED_
#define _NGX_PALLOC_H_INCLUDED_

#include <stdio.h>
#include <errno.h>
#include "ngx_alloc.h"

#define ngx_close_file           close
#define ngx_close_file_n         "close()"

#define ngx_delete_file(name)    unlink((const char *) name)
#define ngx_delete_file_n        "unlink()"

#define NGX_ENOENT        ENOENT
#define ngx_errno         errno

#define  NGX_OK          0
#define  NGX_ERROR      -1
#define  NGX_AGAIN      -2
#define  NGX_BUSY       -3
#define  NGX_DONE       -4
#define  NGX_DECLINED   -5
#define  NGX_ABORT      -6

#define NGX_INVALID_FILE         -1
#define NGX_FILE_ERROR           -1

typedef int               			ngx_err_t;
typedef int                      	ngx_fd_t;
typedef struct ngx_pool_s			ngx_pool_t;
typedef struct ngx_chain_s			ngx_chain_t;

/*
 * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.
 * On Windows NT it decreases a number of locked pages in a kernel.
 */
#define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)

#define NGX_DEFAULT_POOL_SIZE    (16 * 1024)

#define NGX_POOL_ALIGNMENT       16
#define NGX_MIN_POOL_SIZE                                                     \
    ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)),            \
              NGX_POOL_ALIGNMENT)

#ifndef NGX_ALIGNMENT
#define NGX_ALIGNMENT   sizeof(unsigned long)    /* platform word */
#endif

#define ngx_align_ptr(p, a)                                                   \
    (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
			  
typedef void (*ngx_pool_cleanup_pt)(void *data);

typedef struct ngx_pool_cleanup_s  ngx_pool_cleanup_t;

struct ngx_pool_cleanup_s {
    ngx_pool_cleanup_pt   handler;
    void                 *data;
    ngx_pool_cleanup_t   *next;
};

typedef struct ngx_pool_large_s  ngx_pool_large_t;

struct ngx_pool_large_s {
    ngx_pool_large_t     *next;
    void                 *alloc;
};

typedef struct {
    u_char               *last;
    u_char               *end;
    ngx_pool_t           *next;
    ngx_uint_t            failed;
} ngx_pool_data_t;

struct ngx_pool_s {
    ngx_pool_data_t       d;
    size_t                max;
    ngx_pool_t           *current;
    ngx_chain_t          *chain;
    ngx_pool_large_t     *large;
    ngx_pool_cleanup_t   *cleanup;
    void            *log;
};

typedef struct {
    ngx_fd_t              fd;
    u_char               *name;
    void            	 *log;
} ngx_pool_cleanup_file_t;

ngx_pool_t *ngx_create_pool(size_t size, void *log);
void ngx_destroy_pool(ngx_pool_t *pool);
void ngx_reset_pool(ngx_pool_t *pool);

void *ngx_palloc(ngx_pool_t *pool, size_t size);
void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);

ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
void ngx_pool_cleanup_file(void *data);
void ngx_pool_delete_file(void *data);

#endif /* _NGX_PALLOC_H_INCLUDED_ */

        ngx_palloc.c具体代码如下:

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */

#include "ngx_palloc.h"

static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size,
    ngx_uint_t align);
static void *ngx_palloc_block(ngx_pool_t *pool, size_t size);
static void *ngx_palloc_large(ngx_pool_t *pool, size_t size);

void ngx_pool_cleanup_file(void *data);

ngx_pool_t *
ngx_create_pool(size_t size, void *log)
{
    ngx_pool_t  *p;

    p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
    if (p == NULL) {
        return NULL;
    }

    p->d.last = (u_char *) p + sizeof(ngx_pool_t);
    p->d.end = (u_char *) p + size;
    p->d.next = NULL;
    p->d.failed = 0;

    size = size - sizeof(ngx_pool_t);

	// 最多分1页内存大小
    p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;

    p->current = p;
    p->chain = NULL;
    p->large = NULL;
    p->cleanup = NULL;
    p->log = log;

    return p;
}

void
ngx_destroy_pool(ngx_pool_t *pool)
{
    ngx_pool_t          *p, *n;
    ngx_pool_large_t    *l;
    ngx_pool_cleanup_t  *c;

	// 清理资源一些必要操作
    for (c = pool->cleanup; c; c = c->next) {
        if (c->handler) {
            printf("---------------c->handler(c->data)-----------------\n");
            c->handler(c->data);
        }
    }

#if (NGX_DEBUG)

    /*
     * we could allocate the pool->log from this pool
     * so we cannot use this log while free()ing the pool
     */

    for (l = pool->large; l; l = l->next) {
		printf("---------------free: %p-----------------\n", l->alloc);
    }

    for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
		
		printf("---------------free: %p, unused: %u-----------------\n", p, p->d.end - p->d.last);
		
        if (n == NULL) {
            break;
        }
    }

#endif

	// 释放大块内存
    for (l = pool->large; l; l = l->next) {
        if (l->alloc) {
            ngx_free(l->alloc);
        }
    }

	// 释放 pool 内存
    for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
        ngx_free(p);

        if (n == NULL) {
            break;
        }
    }
}

void
ngx_reset_pool(ngx_pool_t *pool)
{
    ngx_pool_t        *p;
    ngx_pool_large_t  *l;

    for (l = pool->large; l; l = l->next) {
        if (l->alloc) {
            ngx_free(l->alloc);
        }
    }

    for (p = pool; p; p = p->d.next) {
        p->d.last = (u_char *) p + sizeof(ngx_pool_t);
        p->d.failed = 0;
    }

    pool->current = pool;
    pool->chain = NULL;
    pool->large = NULL;
}

void *
ngx_palloc(ngx_pool_t *pool, size_t size)
{
#if !(NGX_DEBUG_PALLOC)
    if (size <= pool->max) {
        return ngx_palloc_small(pool, size, 1);
    }
#endif

    return ngx_palloc_large(pool, size);
}

void *
ngx_pnalloc(ngx_pool_t *pool, size_t size)
{
#if !(NGX_DEBUG_PALLOC)
    if (size <= pool->max) {
        return ngx_palloc_small(pool, size, 0);
    }
#endif

    return ngx_palloc_large(pool, size);
}

static ngx_inline void *
ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
{
    u_char      *m;
    ngx_pool_t  *p;

    p = pool->current;

    do {
        m = p->d.last;

        if (align) {
            m = ngx_align_ptr(m, NGX_ALIGNMENT);
        }

		// 如果该 pool 结构中满足size大小的内存,则返回
        if ((size_t) (p->d.end - m) >= size) {
            p->d.last = m + size;

            return m;
        }

		// 指向pool链表的下一个pool结构
        p = p->d.next;

    } while (p);

	// 如果所有的pool链表中没有符合的内存块,则重新申请一个pool
    return ngx_palloc_block(pool, size);
}

static void *
ngx_palloc_block(ngx_pool_t *pool, size_t size)
{
    u_char      *m;
    size_t       psize;
    ngx_pool_t  *p, *new;

    psize = (size_t) (pool->d.end - (u_char *) pool);

    m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
    if (m == NULL) {
        return NULL;
    }

    new = (ngx_pool_t *) m;

    new->d.end = m + psize;
    new->d.next = NULL;
    new->d.failed = 0;

    m += sizeof(ngx_pool_data_t);
    m = ngx_align_ptr(m, NGX_ALIGNMENT);
    new->d.last = m + size;

    for (p = pool->current; p->d.next; p = p->d.next) {
        if (p->d.failed++ > 4) {
            pool->current = p->d.next;
        }
    }

    p->d.next = new;

    return m;
}

static void *
ngx_palloc_large(ngx_pool_t *pool, size_t size)
{
    void              *p;
    ngx_uint_t         n;
    ngx_pool_large_t  *large;

    p = ngx_alloc(size, pool->log);
    if (p == NULL) {
        return NULL;
    }

    n = 0;

    for (large = pool->large; large; large = large->next) {
        if (large->alloc == NULL) {
            large->alloc = p;
            return p;
        }

        if (n++ > 3) {
            break;
        }
    }

    large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
    if (large == NULL) {
        ngx_free(p);
        return NULL;
    }

    large->alloc = p;
    large->next = pool->large;
    pool->large = large;

    return p;
}

void *
ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment)
{
    void              *p;
    ngx_pool_large_t  *large;

    p = ngx_memalign(alignment, size, pool->log);
    if (p == NULL) {
        return NULL;
    }

    large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
    if (large == NULL) {
        ngx_free(p);
        return NULL;
    }

    large->alloc = p;
    large->next = pool->large;
    pool->large = large;

    return p;
}

ngx_int_t
ngx_pfree(ngx_pool_t *pool, void *p)
{
    ngx_pool_large_t  *l;

    for (l = pool->large; l; l = l->next) {
        if (p == l->alloc) {
			
			printf("---------------free: %p-----------------\n", l->alloc);
			
            ngx_free(l->alloc);
            l->alloc = NULL;

            return NGX_OK;
        }
    }

    return NGX_DECLINED;
}

void *
ngx_pcalloc(ngx_pool_t *pool, size_t size)
{
    void *p;

    p = ngx_palloc(pool, size);
    if (p) {
        ngx_memzero(p, size);
    }

    return p;
}

ngx_pool_cleanup_t *
ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
{
    ngx_pool_cleanup_t  *c;

    c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
    if (c == NULL) {
        return NULL;
    }

    if (size) {
        c->data = ngx_palloc(p, size);
        if (c->data == NULL) {
            return NULL;
        }

    } else {
        c->data = NULL;
    }

    c->handler = NULL;
    c->next = p->cleanup;

    p->cleanup = c;

	printf("---------------add cleanup: %p-----------------\n", c);

    return c;
}

void
ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd)
{
    ngx_pool_cleanup_t       *c;
    ngx_pool_cleanup_file_t  *cf;

    for (c = p->cleanup; c; c = c->next) {
        if (c->handler == ngx_pool_cleanup_file) {

            cf = c->data;

            if (cf->fd == fd) {
                c->handler(cf);
                c->handler = NULL;
                return;
            }
        }
    }
}

void
ngx_pool_cleanup_file(void *data)
{
    ngx_pool_cleanup_file_t  *c = data;

	printf("----------file cleanup: fd:%d---------\n", c->fd);

    if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
		printf("----------\"%s\" failed---------\n", c->name);
    }
}

void
ngx_pool_delete_file(void *data)
{
    ngx_pool_cleanup_file_t  *c = data;

    ngx_err_t  err;

	printf("----------file cleanup: fd:%d %s---------\n", c->fd, c->name);

    if (ngx_delete_file(c->name) == NGX_FILE_ERROR) {
        err = ngx_errno;

        if (err != NGX_ENOENT) {
			printf("----------\"%s\" failed---------\n",  c->name);
        }
    }

    if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
		printf("----------\"%s\" failed---------\n",  c->name);
    }
}

        测试主函数主要比较malloc/free申请内存及内存池申请的效率,main.c具体代码如下:

/***********************************************
*    Author : lijd
*    Date   : 2022-11-30
*	 Func   : 测试内存池功能主函数
***********************************************/

#include <stdio.h>

#include "ngx_palloc.h"

#define LOOP_NUM_1	(1024 * 400)
#define LOOP_NUM_2	(1024)
#define MEM_SIZE	16

#define MEM_POOL_SIZE (1024 * 4)

int main(int argc, char *const *argv)
{
	int i, j;
	if(argc == 1)
	{
		printf("-----------------malloc/free---------------\n");
		
		for(i = 0; i < LOOP_NUM_1; i++)
		{
			for(j = 0; j < LOOP_NUM_2; j++)
			{
				void *p = malloc(MEM_SIZE);
			
				if(p == NULL)
				{
					printf("malloc error !\n");
					return -1;
				}
				memset(p, 0, MEM_SIZE);
				free(p);
			}
		}
	}
	else
	{
		printf("-----------------mem pool---------------\n");
		
		for(i = 0; i < LOOP_NUM_1; i++)
		{
			ngx_pool_t *pool = ngx_create_pool(MEM_POOL_SIZE, NULL);
			
			for(j = 0; j < LOOP_NUM_2; j++)
			{
				void *p = ngx_palloc(pool, MEM_SIZE);
				
				if(p == NULL)
				{
					printf("ngx_palloc error !\n");
					return -1;
				}
				memset(p, 0, MEM_SIZE);
			}
			
			ngx_destroy_pool(pool);
		}
	}
	
	return 0;
}

        程序运行结果如下图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadLocal是Java中的一个工具类,主要用于保持线程间的数据隔离。然而,不正确地使用ThreadLocal可能导致内存泄漏。 内存泄漏是指在程序中使用的内存无法被垃圾回收机制回收,导致内存占用不断增加。ThreadLocal的内存泄漏案例如下: 1. 长生命周期的ThreadLocal对象:如果一个ThreadLocal对象的生命周期比应用程序还长,导致ThreadLocal所持有的value对象无法被释放。此时,即使ThreadLocal对象已不再被调用,value对象仍然在ThreadLocalMap中存在,并且无法被垃圾回收,导致内存泄漏。 2. 线程池的ThreadLocal未清理:在使用线程池的环境下,如果某个线程绑定了一个ThreadLocal对象,而未在任务执行结束后手动清除绑定的值,那么该ThreadLocal对象将一直存在于线程池中。如果线程池中的线程数量非常大,将会导致大量ThreadLocal对象未被释放,从而造成内存泄漏。 3. 循环引用:当ThreadLocal对象和其它对象之间存在循环引用关系时,也会导致内存泄漏。因为ThreadLocalMap中的Entry是弱引用,但如果ThreadLocal对象本身被其它对象强引用,就会导致ThreadLocalMap中的Entry无法被清理,从而造成内存泄漏。 为避免ThreadLocal内存泄漏,应注意以下几点: 1. 及时清理ThreadLocal对象:使用完ThreadLocal对象后,应手动调用其remove()方法,确保对应的value对象能够被释放。 2. 避免长生命周期的ThreadLocal对象:尽量将ThreadLocal对象定义为局部变量,而非静态变量或全局变量。 3. 线程池中使用ThreadLocal的安全清理:在使用线程池时,确保在任务执行结束后及时清理线程中绑定的ThreadLocal对象。 4. 避免循环引用:注意ThreadLocal对象与其它对象之间的引用关系,避免产生循环引用。 总而言之,ThreadLocal内存泄漏是由于一些使用不当造成的,合理使用ThreadLocal并进行正确的清理操作,能避免内存泄漏问题的发生。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值