Nginx 고급 데이터 구조 소스 분석 (4) --- 메모리 풀

9443 단어 nginx
메모리 탱크 의 사용 은 Nginx 에 많은 장점 을 가 져 왔 다. 예 를 들 어 메모리 사용 의 편리 함, 논리 코드 의 간소화 와 프로그램 성능 의 향상 등 이다.
몇 가지 관건 적 인 지식 포 인 트 는 다음 과 같다.
(1) 함수 ngxpalloc () 는 메모리 에서 size 크기 의 메모 리 를 분배 하려 고 할 때 두 가지 상황 으로 나 누 었 습 니 다. 하 나 는 size 크기 가 pool - > max 보다 작 으 면 작은 메모리 분배 라 고 합 니 다. 현재 메모리 탱크 노드 가 size 보다 작 으 면 같은 크기 의 메모리 탱크 노드 를 신청 한 다음 에 이 새 메모리 탱크 노드 에서 size 크기 의 메모리 공간 을 분배 합 니 다.만약 size 가 pool - > max 보다 크 면 큰 메모 리 를 분배 합 니 다. 이때 호출 된 함 수 는 운영 체제 에 큰 메모 리 를 직접 신청 합 니 다.
(2) 작은 블록 메모리 의 신청 은 링크 의 끝 부분 에 삽입 되 고 새로운 큰 블록 메모 리 는 링크 앞 에 삽입 된다.
(3) Nginx 는 큰 메모리 에 대한 방출 만 제공 하고 작은 메모리 에 대한 방출 을 제공 하지 않 는 다. 이 는 메모리 풀 에서 분 배 된 메모리 가 메모리 풀 로 회수 되 지 않 고 전체 메모리 풀 을 소각 할 때 만 시스템 메모리 로 회수 된다 는 것 을 의미한다.
(4)ngx_pool_t 의 current 필드: 이 필드 는 메모리 풀 에서 메모 리 를 분배 하 는 시작 노드 를 기록 합 니 다. Nginx 는 메모리 노드 의 총 실패 횟수 가 6 번 이상 일 때 current 는 다음 메모리 노드 를 가리 키 도록 규정 합 니 다.
(5) pool - > max 필드 의 최대 치 를 한 페이지 의 메모리 로 제한 하 는 이 유 는 작은 메모리 와 큰 메모리 의 임계 이기 도 합 니 다. 분 배 된 공간 이 한 페이지 보다 작 을 때 만 캐 시 할 필요 가 있 기 때 문 입 니 다. 그렇지 않 으 면 시스템 인터페이스 malloc () 를 이용 하여 운영 체제 에 직접 신청 하 는 것 이 좋 습 니 다.
각 구조 체 의 정의:
//          
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;      //           ,   1   
    ngx_pool_t           *current; //            
    ngx_chain_t          *chain;  
    ngx_pool_large_t     *large;   //           
    ngx_pool_cleanup_t   *cleanup;  //       
    ngx_log_t            *log;  
};  

메모리 풀 초기 화:
//    size      
ngx_pool_t *  
ngx_create_pool(size_t size, ngx_log_t *log)  
{  
    ngx_pool_t  *p;  
  
    p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);  //         size      
    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;                                //   ,        NULL  
    p->d.failed = 0;                             //           
  
    size = size - sizeof(ngx_pool_t);       //       ,           
    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;  
  
    //       handler  
    for (c = pool->cleanup; c; c = c->next) {  
        if (c->handler) {  
            ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,  
                           "run cleanup: %p", c);  
            c->handler(c->data);  
        }  
    }  
  
    //       
    for (l = pool->large; l; l = l->next) {  
  
        ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);  
  
        if (l->alloc) {  
            ngx_free(l->alloc);      //  free  malloc       
        }  
    }  
  
#if (NGX_DEBUG)  
  
    /* 
     * we could allocate the pool->log from this pool 
     * so we cannot use this log while free()ing the pool 
     */  
  
    for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {  
        ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0,  
                       "free: %p, unused: %uz", p, p->d.end - p->d.last);  
  
        if (n == NULL) {  
            break;  
        }  
    }  
  
#endif  
  
    //             ngx_pool_t  
    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);  
        }  
    }  
  
    //     ,    last       
    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)  
{  
    u_char      *m;  
    ngx_pool_t  *p;  
  
    if (size <= pool->max) {  //      , size     
  
        p = pool->current;  
  
        do {  
            m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT); //   d.last      
  
            if ((size_t) (p->d.end - m) >= size) {        //               
                p->d.last = m + size;        //    d.last  
  
                return m;       //      
            }  
  
            p = p->d.next;       //                
  
        } while (p);  
  
        //    ,             
        return ngx_palloc_block(pool, size);  
    }  
  
    return ngx_palloc_large(pool, size);    //         
}  
  
//    (       )  
void *  
ngx_pnalloc(ngx_pool_t *pool, size_t size)  
{  
    u_char      *m;  
    ngx_pool_t  *p;  
  
    if (size <= pool->max) {  //     
  
        p = pool->current;  
  
        do {  
            m = p->d.last;  
  
            if ((size_t) (p->d.end - m) >= size) {  
                p->d.last = m + size;  
  
                return m;  
            }  
  
            p = p->d.next;  
  
        } while (p);  
  
        return ngx_palloc_block(pool, size);    //          
    }  
  
    return ngx_palloc_large(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);   //    ngx_pool_data_t,   ngx_pool_t       
    m = ngx_align_ptr(m, NGX_ALIGNMENT);  
    new->d.last = m + size;      //            
      
    //                 5  , 6 ,current             
    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);      //  malloc      
    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) {       //    4 , 5   break,            
            break;  
        }  
    }  
  
    large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); //            
    if (large == NULL) {  
        ngx_free(p);  
        return NULL;  
    }  
  
    large->alloc = p;    //          
  
    //  large    
    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(pool, sizeof(ngx_pool_large_t)); //             
    if (large == NULL) {  
        ngx_free(p);  
        return NULL;  
    }  
  
    //      ngx_pool_t     
    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) {  
            ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,  
                           "free: %p", l->alloc);  
            ngx_free(l->alloc);  
            l->alloc = NULL; //     
  
            return NGX_OK;  
        }  
    }  
  
    return NGX_DECLINED;  
}  

좋은 웹페이지 즐겨찾기