가비지 수집 메커니즘
가비지 수집 메커니즘은 동적 저장소 할당 체계입니다. 프로그램에 더 이상 필요하지 않은 할당된 메모리 블록을 자동으로 해제합니다. 자동으로 메모리를 회수하는 프로세스를 가비지 수집이라고 합니다. 가비지 수집 메커니즘을 사용하면 프로그래머는 프로그램 메모리 할당에 대해 너무 많이 걱정하지 않아도 되므로 비즈니스 로직에 더 많은 에너지를 쏟을 수 있습니다. 오늘날 널리 사용되는 다양한 언어 중에서 가비지 수집 메커니즘은 차세대 언어의 공통된 특징입니다.
가비지 생성
문자열, 배열, 객체 등과 같은 PHP7의 복잡한 유형에는 헤더에 gc가 있습니다. 이 gc의 기능은 가비지 수집을 지원하는 것입니다. 변수를 할당하거나 전송할 때 값의 참조 개수가 증가합니다. 변수가 unset, return 등에 의해 해제될 때 뺄셈 후 참조 개수가 0이 되는 경우 해당 참조 번호를 뺍니다. 이는 변수의 기본적인 재활용 과정입니다.
그러나 이 메커니즘으로 해결할 수 없는 한 가지 문제가 있는데, 바로 순환 참조 문제입니다.
순환 참조란 무엇인가요? 간단히 말해서, 변수 내부에 저장된 값은 변수 자체를 참조합니다. 이 비교는 배열 및 객체 유형의 변수에서 자주 발생합니다.
먼저 참조, 즉 zend_reference 유형에 대해 이야기하겠습니다. 이것은 PHP7의 새로운 변수 유형입니다. 변수에 "&" 연산이 사용되면 실제로 이 구조가 생성됩니다. 해당 값에.
예:
// 当进行如下赋值操作时 $a = 'hello'; // $a -> zend_string $b = $a; // $b,$a -> zend_string $c = &$b; // $c,$b -> zval(type = IS_REFERENCE, refcount = 2) -> zend_string
결국 다음과 같이 됩니다:
즉, $b와 $c의 zval은 중간 구조 zend_reference를 통해 최종 zend_string을 가리킵니다.
순환 참조 문제로 돌아가서, 배열 순환 참조의 예는 다음과 같습니다.
$a = [1]; $a[] = &$a; unset($a);
& 연산을 사용한 후 변수 a는 참조 유형이 되고 참조 카운트 refcount는 2가 되며 자체 변수에 할당됩니다. 요소, 즉 변수 a는 자체 참조가 됩니다.
자세한 내용은 다음과 같습니다.
Unset 후에는 아래 그림과 같습니다.
즉, $a가 위치한 zval 타입은 IS_UNDEF가 되고, 참조 횟수는 $a가 됩니다. zend_reference 구조체는 1만큼 감소하지만 여전히 0보다 큽니다. 이때 구조체의 이 부분을 처리하지 않으면 메모리 누수가 발생할 수 있습니다. 여기서 이 부분을 버퍼로 수집한 다음 재활용하려면 가비지 수집기가 필요합니다.
재활용 프로세스
변수가 줄어들 때 참조 횟수가 0보다 큰 경우, PHP는 이 변수에 대해 즉시 가비지 식별 및 재활용을 수행하지 않고 버퍼가 가득 찰 때까지( 10000) 버퍼에 넣습니다. 그런 다음 버퍼에 추가되는 것은 zend_value 변수의 gc입니다. 현재 가비지는 배열과 객체의 두 가지 유형에만 나타납니다. 위에서는 배열의 경우입니다. 멤버 속성 참조. 개체 자체로 인해 다른 유형에서는 해당 변수의 멤버가 변수 자체를 참조하지 않으므로 가비지 수집에서는 이 두 가지 유형의 변수만 처리합니다.
gc zend_refcounted_h의 구조는 다음과 같습니다.
typedef struct _zend_refcounted_h { uint32_t refcount; // 记录 zend_value 的引用数 union { struct { zend_uchar type, // zend_value的类型, 与zval.u1.type一致 zend_uchar flags, uint16_t gc_info // GC信息,记录在 gc 池中的位置和颜色,垃圾回收的过程会用到 } v; uint32_t type_info; } u; } zend_refcounted_h;
변수는 버퍼에 한 번만 추가할 수 있습니다. 반복 추가를 방지하기 위해 변수가 추가된 후 zend_refcounted_h.gc_info는 보라색으로 표시되는 GC_PURPLE로 설정됩니다. , 앞으로 반복해서 삽입되지 않습니다.
가비지 버퍼는 이중 연결 목록입니다. 버퍼가 가득 차면 가비지 검사 프로세스가 시작됩니다. 즉, 버퍼를 순회하고 현재 변수의 모든 멤버를 순회한 다음 해당 멤버의 참조 횟수를 1만큼 줄입니다. member에는 하위 멤버도 포함) 재귀 순회, 즉 깊이 우선 순회를 수행하고 마지막으로 현재 변수의 참조를 확인하여 0으로 감소하면 가비지입니다. 이 알고리즘의 핵심 원리는 멤버가 자신을 참조하여 가비지가 발생하고 모든 멤버에 대한 참조를 줄이는 것입니다. 최종 변수 자체의 참조 횟수가 0이 되면 모든 참조가 자체 변수에서 온다는 의미입니다. 더 이상 사용하지 않으면 쓰레기이므로 재활용해야 합니다. 그렇지 않으면 가비지가 아니므로 버퍼에서 제거해야 함을 의미합니다. 구체적인 프로세스는 다음과 같습니다.
(1) 버퍼 연결 목록의 루트부터 순회를 시작하고 현재 값을 회색으로 표시한 다음(zend_refcounted_h.gc_info가 GC_GREY로 설정됨) 멤버의 깊이 우선 순회를 수행합니다. 현재 값, 멤버 값에서 refcount를 1로 설정하고 회색으로 표시합니다.
(2) 버퍼 연결 리스트를 반복적으로 순회하여 현재 값 참조가 0인지 확인합니다. 0이면 실제로 가비지임을 의미하며 0이 아닌 경우 가능성을 배제합니다. 이는 모든 참조가 자신의 멤버로부터 온다는 의미입니다. 이는 가비지가 아닌 외부 참조가 있음을 의미합니다. 이때 (1) 단계에서 멤버의 참조 카운트가 1만큼 감소하므로 이를 복원해야 합니다. 모든 멤버 순회가 수행되면 멤버 참조 개수가 1만큼 증가하고 검정색으로 표시됩니다.
(3) 버퍼 연결 목록을 다시 순회하고 루트 연결 목록에서 GC_WHITE가 아닌 노드를 제거합니다. 진짜 쓰레기가 되어 마침내 이 쓰레기를 치워버리세요.
위 내용은 PHP7 가비지 수집 메커니즘(GC) 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!