>  기사  >  백엔드 개발  >  PHP 소스 코드 34에 대한 간략한 논의: PHP5.3에 새로 추가된 가비지 수집 메커니즘(Garbage Collection)

PHP 소스 코드 34에 대한 간략한 논의: PHP5.3에 새로 추가된 가비지 수집 메커니즘(Garbage Collection)

不言
不言원래의
2018-06-29 10:07:011000검색

이 글에서는 PHP 소스 코드 34에 대해 주로 소개합니다. PHP5.3에 새로 추가된 가비지 컬렉션 메커니즘은 이제 특정 참고 가치가 있어 도움이 필요한 모든 사람들과 공유합니다.

PHP 소스코드에 대해 간단히 이야기해보자 34: PHP5.3에 새로 추가된 가비지 컬렉션 메커니즘(Garbage Collection)
이전 글에서는 PHP 소스코드에 대해 이야기해보자. 33: PHP5.3의 새로운 가비지 수집 메커니즘(Garbage Collection) 기본에서는 가비지 수집 메커니즘에 대한 몇 가지 기본 지식을 소개합니다. 오늘 우리는 초기화를 살펴보고 가비지 버퍼와 가비지 수집 프로세스를 추가합니다.
공식 문서를 보려면 Garbage Collection을 클릭하세요
중국어 버전 주소: http://docs.php.net/manual/zh/features.gc.php
【초기화】#🎜 🎜# zend/zend_gc.c의 121번째 줄에는 gc의 초기화를 구현하는 gc_init 함수가 있습니다. 코드는 다음과 같습니다:

 ZEND_API void gc_init(TSRMLS_D){
if (GC_G(buf) == NULL && GC_G(gc_enabled)) {
GC_G(buf) = (gc_root_buffer*) malloc(sizeof(gc_root_buffer) * GC_ROOT_BUFFER_MAX_ENTRIES);
GC_G(last_unused) = &GC_G(buf)[GC_ROOT_BUFFER_MAX_ENTRIES];
gc_reset(TSRMLS_C);
}}

123번째 줄은 비어 있는지, gc가 비어 있는지 여부를 결정합니다. 둘 다 true이면 124번째 줄로 이동합니다.

124번째 줄은 malloc을 직접 호출하여 10,000gc_root_buffer 메모리를 할당합니다.
Line 125는 전역 변수 last_unused를 gc 버퍼의 끝 위치로 설정합니다.
126행은 전체 가비지 수집 메커니즘을 재설정합니다. 코드는 다음과 같이 zend/zend_gc.c의 88행에서 시작합니다.

ZEND_API void gc_reset(TSRMLS_D){
GC_G(gc_runs) = 0;
GC_G(collected) = 0; #if GC_BENCH
GC_G(root_buf_length) = 0;
GC_G(root_buf_peak) = 0;
GC_G(zval_possible_root) = 0;
GC_G(zobj_possible_root) = 0;
GC_G(zval_buffered) = 0;
GC_G(zobj_buffered) = 0;
GC_G(zval_remove_from_buffer) = 0;
GC_G(zobj_remove_from_buffer) = 0;
GC_G(zval_marked_grey) = 0;
GC_G(zobj_marked_grey) = 0;#endif 
GC_G(roots).next = &GC_G(roots);
GC_G(roots).prev = &GC_G(roots); if (GC_G(buf)) {
GC_G(unused) = NULL;
GC_G(first_unused) = GC_G(buf); 
GC_G(zval_to_free) = NULL;
} else {
GC_G(unused) = NULL;
GC_G(first_unused) = NULL;
GC_G(last_unused) = NULL;
}}

90~91행은 GC 수의 통계를 설정합니다. 실행(gc_runs)되고 gc의 가비지(수집) 수는 0입니다.

106~107행은 이중 연결 리스트의 헤드 노드의 이전 노드와 다음 노드가 자신을 가리키도록 설정합니다.

gc_enabled의 경우 기본적으로 활성화되어 있으며 php.ini에서 구성할 수 있습니다.

구현 코드는 zend/zend.c의 93번째 라인에 다음과 같습니다:

STD_ZEND_INI_BOOLEAN("zend.enable_gc","1",ZEND_INI_ALL,OnUpdateGCEnabled,   gc_enabled, zend_gc_globals,        gc_globals)

초기화 호출은 zend/zend.c의 79번째 라인에 있습니다

 static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */{
OnUpdateBool(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); if (GC_G(gc_enabled)) {
gc_init(TSRMLS_C);
} return SUCCESS;}
#🎜🎜 #[가비지 버퍼 영역에 추가]

Track PHP 소스 코드 zend/zend_execute_API.c 424

[_zval_ptr_dtor] -> [GC_ZVAL_CHECK_POSSIBLE_ROOT()] -> gc_zval_possible_root() ]#🎜 🎜#gc_zval_check_possible_root() 함수에서는 배열과 객체에 대해 가비지 수집 작업만 수행됩니다

gc_zval_possible_root 함수의 코드는 다음과 같습니다

ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC){
if (UNEXPECTED(GC_G(free_list) != NULL &&
               GC_ZVAL_ADDRESS(zv) != NULL &&
           GC_ZVAL_GET_COLOR(zv) == GC_BLACK) &&
           (GC_ZVAL_ADDRESS(zv) < GC_G(buf) ||
            GC_ZVAL_ADDRESS(zv) >= GC_G(last_unused))) {
/* The given zval is a garbage that is going to be deleted by
 * currently running GC */
return;
} if (zv->type == IS_OBJECT) {
GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv);
return;
} 
GC_BENCH_INC(zval_possible_root); if (GC_ZVAL_GET_COLOR(zv) != GC_PURPLE) {
GC_ZVAL_SET_PURPLE(zv); if (!GC_ZVAL_ADDRESS(zv)) {
gc_root_buffer *newRoot = GC_G(unused); if (newRoot) {
GC_G(unused) = newRoot->prev;
} else if (GC_G(first_unused) != GC_G(last_unused)) {
newRoot = GC_G(first_unused);
GC_G(first_unused)++;
} else {
if (!GC_G(gc_enabled)) {
GC_ZVAL_SET_BLACK(zv);
return;
}
zv->refcount__gc++;
gc_collect_cycles(TSRMLS_C);
zv->refcount__gc--;
newRoot = GC_G(unused);
if (!newRoot) {
return;
}
GC_ZVAL_SET_PURPLE(zv);
GC_G(unused) = newRoot->prev;
} 
newRoot->next = GC_G(roots).next;
newRoot->prev = &GC_G(roots);
GC_G(roots).next->prev = newRoot;
GC_G(roots).next = newRoot; 
GC_ZVAL_SET_ADDRESS(zv, newRoot); 
newRoot->handle = 0;
newRoot->u.pz = zv; 
GC_BENCH_INC(zval_buffered);
GC_BENCH_INC(root_buf_length);
GC_BENCH_PEAK(root_buf_peak, root_buf_length);
}
}}
#🎜 🎜#Lines 132~140 zval 매듭 확인 포인트 정보가 노드 버퍼에 들어갔는지 여부, 노드 버퍼에 넣었다면 직접 반환하여 성능을 최적화할 수 있음

Lines 142 ~145 객체 노드를 직접 처리하고 더 이상 후속 작업을 수행하지 않습니다.

149행은 노드가 보라색으로 표시되었는지 여부를 결정합니다. 이는 더 이상 노드 버퍼에 추가되지 않습니다. 노드가 버퍼 작업에 추가만 수행하는지 확인하는 것입니다.

150행은 노드의 색상을 보라색으로 표시하여 이 노드가 버퍼에 추가되었으며 다음에 추가할 필요가 없음을 나타냅니다.

알아보기 153~157번째 줄에는 새 노드의 위치입니다. 버퍼가 가득 차면 가비지 수집 작업이 수행됩니다.

176~184번째 줄은 버퍼가 위치한 이중 연결 리스트에 새로운 노드를 추가합니다.

[가비지 수집 프로세스]

gc_zval_possible_root 함수에서 버퍼가 가득 차면 프로그램은 gc_collect_cycles 함수를 호출하여 가비지 수집 작업을 수행합니다. zend/zend_gc.c 파일의 615번째 줄부터 구현 코드는 다음과 같습니다:

 ZEND_API int gc_collect_cycles(TSRMLS_D){
int count = 0; if (GC_G(roots).next != &GC_G(roots)) {
zval_gc_info *p, *q, *orig_free_list, *orig_next_to_free; if (GC_G(gc_active)) {
return 0;
}
GC_G(gc_runs)++;
GC_G(zval_to_free) = FREE_LIST_END;
GC_G(gc_active) = 1;
gc_mark_roots(TSRMLS_C);
gc_scan_roots(TSRMLS_C);
gc_collect_roots(TSRMLS_C); 
orig_free_list = GC_G(free_list);
orig_next_to_free = GC_G(next_to_free);
p = GC_G(free_list) = GC_G(zval_to_free);
GC_G(zval_to_free) = NULL;
GC_G(gc_active) = 0; /* First call destructors */
while (p != FREE_LIST_END) {
if (Z_TYPE(p->z) == IS_OBJECT) {
if (EG(objects_store).object_buckets &&
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0 &&
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor &&
!EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called) { 
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called = 1;
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount++;
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor(EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.object, Z_OBJ_HANDLE(p->z) TSRMLS_CC);
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount--;
}
}
count++;
p = p->u.next;
} /* Destroy zvals */
p = GC_G(free_list);
while (p != FREE_LIST_END) {
GC_G(next_to_free) = p->u.next;
if (Z_TYPE(p->z) == IS_OBJECT) {
if (EG(objects_store).object_buckets &&
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0) {
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1;
Z_TYPE(p->z) = IS_NULL;
zend_objects_store_del_ref_by_handle_ex(Z_OBJ_HANDLE(p->z), Z_OBJ_HT(p->z) TSRMLS_CC);
}
} else if (Z_TYPE(p->z) == IS_ARRAY) {
Z_TYPE(p->z) = IS_NULL;
zend_hash_destroy(Z_ARRVAL(p->z));
FREE_HASHTABLE(Z_ARRVAL(p->z));
} else {
zval_dtor(&p->z);
Z_TYPE(p->z) = IS_NULL;
}
p = GC_G(next_to_free);
} /* Free zvals */
p = GC_G(free_list);
while (p != FREE_LIST_END) {
q = p->u.next;
FREE_ZVAL_EX(&p->z);
p = q;
}
GC_G(collected) += count;
GC_G(free_list) = orig_free_list;
GC_G(next_to_free) = orig_next_to_free;
} return count;}

619번째 줄은 버퍼가 비어 있는지 여부를 결정합니다. 비어 있으면 가비지 수집 작업이 수행되지 않습니다. 수행됨

622행은 가비지 수집 작업이 진행 중인지 확인합니다. 진행 중이면 직접 반환합니다.
625~627행 가비지 수집 작업 수에 1을 더하고 사용 가능 목록을 초기화한 후 설정합니다. gc_active를 1로 설정하여 가비지 반환이 진행 중임을 나타냅니다.

628행은 공식 문서에 있는 알고리즘의 B단계입니다. 이 알고리즘은 가능한 모든 루트를 찾은 후 깊이 우선 검색을 사용합니다. 변수 컨테이너는 동일한 변수 컨테이너에 액세스하지 않도록 1″씩 감소합니다. "1"을 두 번 빼고 1만큼 감소된 항목을 회색으로 표시합니다.

Line 629 이것이 알고리즘의 C단계입니다. 알고리즘은 다시 한번 각 루트 노드에 대해 깊이 우선 검색을 사용하고 참조 개수가 0이면 변수 컨테이너가 0보다 큰 경우 작업이 수행됩니다. 이 시점에서 깊이 우선 탐색을 사용하여 참조 카운트를 1씩 감소시키는 작업이 재개된 다음 참조 카운트가 1만큼 증가합니다.
라인 630의 알고리즘의 마지막 단계 D, 알고리즘이 순회합니다. 거기에서 변수 컨테이너 루트(zval 루트)를 제거하는 동시에 이전 단계에서 흰색으로 표시된 변수 컨테이너가 있는지 확인합니다. [gc_collect_cycles() -> gc_collect_roots() -> zval_collect_white() ]에서 흰색으로 표시된 노드가 전역 변수 zval_to_free 목록에 추가됩니다.
라인. 632~633 전역 변수 free_list 및 next_to_free를 해당 임시 변수에 저장하고 마지막에 현재 상태로 복원됩니다.
634~635행은 지워야 할 목록을 초기화하고 zval 목록을 지웁니다. 가비지 수집 작업 상태를 비활성 상태로 설정합니다.
639~655번째 줄은 소멸자를 처음으로 호출하고 지워진 변수의 수를 계산합니다.
657~678번째 줄의 변수 지우기#🎜🎜 # 682~686행 메모리 해제
687~689행은 가비지 번호 통계 처리 및 free_list 및 next_to_free 변수 복원# 🎜🎜#
위 내용은 이 글의 전체 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지를 주목해주세요

관련 추천:

PHP 소스 코드에 대한 간략한 토론 33: PHP5.3의 새로운 가비지 수집 메커니즘(가비지 수집)의 기본

PHP 소스 코드에 대한 간략한 토론 32: PHP의 emalloc/efree 레이어 및 힙 메모리 풀) 레이어

PHP 소스 코드 29에 대한 간략한 토론: 인터페이스 상속에 대하여

위 내용은 PHP 소스 코드 34에 대한 간략한 논의: PHP5.3에 새로 추가된 가비지 수집 메커니즘(Garbage Collection)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.