Nginx 소스 코드 분석 - 메모리 탱크

6855 단어
Nginx 의 메모리 풀 은 매우 정교 하 게 실현 되 었 고 코드 도 매우 간결 하 다.전체적으로 말 하면 모든 메모리 탱크 는 기본적으로 하나의 취지 이다. 큰 메모 리 를 신청 하여 '가 는 물 과 긴 흐름' 을 피한다.
1. 메모리 풀 만 들 기
nginx 메모리 탱크 는 주로 다음 두 가지 구조 로 유지 되 는데 그들 은 각각 메모리 탱크 의 머리 와 데이터 부 를 유지 했다.이 데이터 부 는 사용자 가 작은 블록 메모 리 를 할당 할 수 있 는 곳 입 니 다.
//              ,       。 
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;	//     chain   
ngx_pool_large_t *large;	//       ,   max      
ngx_pool_cleanup_t *cleanup;	//            ,       。 
ngx_log_t *log; 
}; 

위의 두 구조 가 있 으 면 메모리 풀 을 만 들 수 있 습 니 다. nginx 는 메모리 풀 을 만 드 는 인 터 페 이 스 는: ngx 입 니 다.pool_t *ngx_create_pool (size t size, ngx log t * log) (src / core / ngx palloc. c 에 있 음);이 함 수 를 호출 하면 크기 가 size 인 메모리 풀 을 만 들 수 있 습 니 다.여기 서 나 는 메모리 탱크 의 구조 도 를 보 여 주 었 기 때문에 구체 적 인 코드 분석 을 하지 않 았 다.ngx_create_pool 인터페이스 함 수 는 위의 그림 과 같은 큰 메모 리 를 분배 한 다음 에 각 머리 필드 (위의 그림 의 컬러 부분) 를 초기 화 하 는 것 입 니 다.빨간색 이 표시 하 는 네 개의 필드 는 바로 상기 첫 번 째 구조 에서 나 온 것 입 니 다. 데이터 부분 을 유지 하 는 것 입 니 다. 그림 에서 알 수 있 듯 이 last 는 사용자 가 메모리 탱크 에서 새 메모리 를 분배 하 는 시작 위치 입 니 다. end 는 이 메모리 탱크 의 끝 위치 이 고 모든 분 배 된 메모리 가 end 를 초과 할 수 없습니다.파란색 이 표시 하 는 max 필드 의 값 은 전체 데이터 부분의 길이 와 같 습 니 다. 사용자 가 요청 한 메모리 가 max 보다 클 때 사용자 가 요청 한 것 이 큰 메모리 라 고 생각 합 니 다. 이 때 보라색 이 표시 하 는 large 필드 아래 에서 따로 분배 해 야 합 니 다.사용자 가 요청 한 메모리 가 max 보다 크 지 않 으 면 작은 메모리 신청 입 니 다. 데이터 부분 에서 직접 분 배 됩 니 다. 이 때 last 포인터 가 이동 합 니 다.
2. 작은 블록 메모리 할당 (size < = max)
위 에 사용 가능 한 메모리 풀 을 만 들 었 고 작은 메모리 의 배분 문제 도 언급 했다.nginx 가 사용자 에 게 제공 하 는 메모리 할당 인 터 페 이 스 는 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_palloc 와 ngxpnalloc 는 메모리 탱크 에서 size 크기 의 메모 리 를 분배 합 니 다. 작은 메모리 인지 큰 메모리 인지 크기 에 따라 결 정 됩 니 다.그들의 차이 점 은 palloc 가 얻 은 메모리 가 정렬 되 어 있 고 pnalloc 는 그렇지 않다 는 것 이다.ngx_pcalloc 는 palloc 를 직접 호출 하여 메모 리 를 분배 한 다음 0 초기 화 작업 을 합 니 다.ngx_pmemalign 은 size 크기 의 메모 리 를 할당 하고 alignment 에 따라 정렬 한 다음 large 필드 에 걸 어 큰 메모리 로 처리 합 니 다.다음은 작은 블록 메모 리 를 분배 하 는 모델 을 도형 으로 보 여 줍 니 다. 위의 그림 에서 이 메모리 탱크 모델 은 위의 세 개의 작은 메모리 탱크 로 구성 되 어 있 습 니 다. 첫 번 째 메모리 탱크 에 남 은 메모리 가 분배 되 지 않 아서 두 번 째 메모리 탱크 를 만 들 었 습 니 다. 세 번 째 메모리 탱크 는 앞의 두 개의 메모리 탱크 의 나머지 부분 이 분배 되 지 않 았 기 때 문 입 니 다.그래서 세 번 째 메모리 풀 을 만들어 사용자 의 수 요 를 만족 시 켰 습 니 다.그림 에서 볼 수 있 습 니 다. 모든 작은 메모리 풀 은 단 방향 링크 로 유지 되 어 있 습 니 다.여기 에는 failed 와 current 필드 에 관심 을 가 져 야 할 두 필드 가 있 습 니 다.failed 는 현재 이 메모리 탱크 의 남 은 사용 가능 한 메모리 가 사용자 의 할당 요청 횟수 를 만족 시 키 지 못 한 다 는 것 을 나타 낸다. 즉, 하나의 할당 요청 이 온 후에 이 메모리 탱크 에 원 하 는 메모 리 를 할당 하지 못 하면 failed 는 1 이 증가 할 것 이다.이 할당 요청 은 다음 메모리 풀 에 전 달 됩 니 다. 다음 메모리 풀 도 만족 하지 못 하면 failed 도 1 을 추가 한 다음 요청 을 만족 시 킬 때 까지 계속 전달 합 니 다. (기 존 메모리 풀 이 없 으 면 새로운 메모리 풀 을 만 들 것 입 니 다)current 필드 는 failed 가 증가 함 에 따라 달라 집 니 다. current 가 가리 키 는 메모리 풀 의 failed 가 4 에 이 르 면 current 는 다음 메모리 풀 을 가리 킵 니 다.추측: 4 이 값 은 작가 의 경험 치 또는 통계 값 이 어야 합 니 다.
3. 큰 메모리 의 할당 (size > max)
큰 메모리 의 분배 요청 은 메모리 탱크 에 메모 리 를 직접 분배 하여 만족 시 키 지 않 고 운영 체제 에 이러한 메모 리 를 직접 신청 합 니 다 (malloc 를 직접 사용 하여 메모 리 를 분배 하 는 것 과 같 습 니 다). 그리고 이 메모 리 를 메모리 탱크 머리의 large 필드 에 걸 어 놓 습 니 다.메모리 탱크 의 역할 은 작은 메모리 탱크 의 빈번 한 신청 문 제 를 해결 하 는 데 있다. 이런 큰 메모리 에 대해 서 는 직접 신청 하 는 것 을 참 을 수 있다.마찬가지 로 큰 메모리 신청 모델 을 도형 으로 보 여 줍 니 다. 모든 큰 메모리 가 하나의 머리 구조 (next & alloc) 에 대응 하 는 것 을 주의 하 십시오. 이 머리 구 조 는 모든 큰 메모 리 를 하나의 링크 로 연결 하 는 데 사 용 됩 니 다.이 머리 구 조 는 운영 체제 에 직접 신청 한 것 이 아니 라 작은 메모리 (머리 구조 에 바이트 가 몇 개 없 음) 로 메모리 풀 에 직접 신청 한 것 이다.이러한 큰 블록 안에 사용 한 후에 가장 먼저 방출 하고 메모리 공간 을 절약 해 야 할 수도 있 기 때문에 nginx 는 인터페이스 함 수 를 제공 합 니 다: ngxint_t ngx_pfree(ngx_pool_t *pool, void *p);이 함 수 는 특정한 메모리 탱크 의 큰 메모 리 를 방출 하 는 데 사 용 됩 니 다. p 는 큰 메모리 의 주소 입 니 다.ngx_pfree 는 큰 메모리 만 방출 하고 대응 하 는 머리 구 조 를 방출 하지 않 습 니 다. 왜냐하면 머리 구 조 는 작은 안에 메모리 탱크 에 존재 하 는 것 으로 신청 되 기 때 문 입 니 다.남 겨 진 머리 구 조 는 다음 에 큰 메모 리 를 신청 할 것 이다.
4. cleanup 자원
메모리 탱크 에 마 운 트 된 모든 자원 이 순환 링크 를 형성 하 는 것 을 볼 수 있 습 니 다. 걸 어 오 면서 링크 와 같은 간단 해 보 이 는 데이터 구조 가 자주 사용 되 는 것 을 발견 할 수 있 습 니 다.그림 에서 알 수 있 듯 이 청소 해 야 할 모든 자원 은 머리 구조 에 대응 합 니 다. 이 구조 에는 관건 적 인 필드 handler 가 있 습 니 다. handler 는 함수 포인터 입 니 다. 자원 을 메모리 풀 에 마 운 트 할 때 자원 을 청소 하 는 함수 도 이 handler 에 등록 합 니 다.메모리 탱크 가 cleanup 를 청소 할 때 이 handler 를 사용 하여 해당 하 는 자원 을 청소 하 는 것 이다.예 를 들 어 우 리 는 열 린 파일 설명 자 를 자원 으로 메모리 풀 에 마 운 트 할 수 있 고 파일 설명 을 닫 는 함 수 를 handler 에 등록 할 수 있 습 니 다. 그러면 메모리 풀 이 풀 릴 때 우리 가 제공 하 는 닫 기 파일 함수 로 파일 설명자 자원 을 처리 합 니 다.
5. 메모리 의 방출
nginx 는 사용자 에 게 메모리 신청 인터페이스 만 제공 하고 메모리 의 인 터 페 이 스 를 방출 하지 않 았 습 니 다. 그러면 nginx 는 어떻게 메모리 방출 을 완 료 했 습 니까?계속 신청 할 수 는 없 잖 아, 석방 할 수 는 없 잖 아.이 문제 에 대해 nginx 는 웹 server 응용 특수 장면 을 이용 하여 완성 했다.웹 서버 는 항상 connection 과 request 를 끊임없이 받 아들 이기 때문에 nginx 는 메모리 풀 을 서로 다른 등급 으로 나 누 었 습 니 다. 프로 세 스 급 메모리 풀, connection 급 메모리 풀, request 급 메모리 풀 이 있 습 니 다.즉, 워 커 프로 세 스 를 만 들 때 이 워 커 프로 세 스 를 위 한 메모리 풀 을 만 듭 니 다. 새로운 연결 이 오 면 워 커 프로 세 스 의 메모리 풀 에 메모리 풀 을 만 듭 니 다.연결 에 request 가 도착 하면 연 결 된 메모리 풀 에 request 를 위 한 메모리 풀 을 만 듭 니 다.이렇게 하면 request 가 처 리 된 후에 request 의 전체 메모리 풀 을 방출 하고 연결 이 끊 긴 후에 연 결 된 메모리 풀 을 방출 합 니 다.따라서 메모리 의 분배 도 있 고 방출 도 보장 된다.
요약: 메모리 의 배분 과 방출 을 통 해 알 수 있 듯 이 nginx 는 작은 메모리 의 신청 을 한데 모 아 신청 한 다음 에 같이 방출 합 니 다.잦 은 메모리 신청 을 피하 고 메모리 파편 발생 을 줄 이 는 등 문 제 를 피 했다.
Ref: http://www.alidata.org/archives/1390

좋은 웹페이지 즐겨찾기