(추천 튜토리얼: PHP 비디오 튜토리얼)
각 PHP 변수는 zval이라는 변수 컨테이너에 존재합니다.
zval 변수 컨테이너에는 변수의 유형과 값을 포함하는 것 외에도 2바이트의 추가 정보도 포함됩니다.
첫 번째는 is_ref이며, 이 변수가 참조 컬렉션에 속하는지 여부를 식별하는 데 사용되는 부울 값입니다. 이 바이트를 통해 PHP 엔진은 일반 변수와 참조 변수를 구별할 수 있습니다. PHP에서는 사용자가 &를 사용하여 사용자 정의 참조를 사용할 수 있으므로 zval 변수 컨테이너에는 메모리 사용을 최적화하는 내부 참조 계산 메커니즘도 있습니다.
두 번째 추가 바이트는 refcount이며, 이는 이 zval 변수 컨테이너를 가리키는 변수 수를 나타냅니다.
모든 기호는 기호 테이블에 존재하며, 각 기호에는 범위가 있고 기본 스크립트(예: 브라우저를 통해 요청된 스크립트)와 각 함수 또는 메서드에도 범위가 있습니다.
변수에 상수 값이 할당되면 zval 변수 컨테이너가 생성됩니다
Xdebug가 설치되어 있으면 xdebug_debug_zval()
<?php $a = "new string"; xdebug_debug_zval('a'); //结果 a: (refcount=1, is_ref=0)='new string'
하나의 변수를 다른 변수에 할당하면 참조 수가 늘어납니다
<?php $a = "new string"; $b = $a; xdebug_debug_zval( 'a' ); //结果 a: (refcount=2, is_ref=0)='new string'
unset()을 사용하여 참조 수를 줄입니다
유형과 값을 포함하는 변수 컨테이너가 제거됩니다. 메모리 삭제
<?php $a = "new string"; $c = $b = $a; xdebug_debug_zval( 'a' ); unset( $b, $c ); xdebug_debug_zval( 'a' ); //结果 a: (refcount=3, is_ref=0)='new string' a: (refcount=1, is_ref=0)='new string'
<?php $a = array( 'meaning' => 'life', 'number' => 42 ); xdebug_debug_zval( 'a' ); //结果 a: (refcount=1, is_ref=0)=array ( 'meaning' => (refcount=1, is_ref=0)='life', 'number' => (refcount=1, is_ref=0)=42 )
배열에 기존 요소 추가
<?php $a = array( 'meaning' => 'life', 'number' => 42 ); $a['life'] = $a['meaning']; xdebug_debug_zval( 'a' ); //结果 a: (refcount=1, is_ref=0)=array ( 'meaning' => (refcount=2, is_ref=0)='life', 'number' => (refcount=1, is_ref=0)=42, 'life' => (refcount=2, is_ref=0)='life' )
배열에서 요소를 삭제하는 것은
범위에서 변수를 삭제하는 것과 유사합니다.
삭제 후 "배열의 요소가 위치한 컨테이너의 참조 횟수" 값이 줄어듭니다
<?php $a = array( 'meaning' => 'life', 'number' => 42 ); $a['life'] = $a['meaning']; unset( $a['meaning'], $a['number'] ); xdebug_debug_zval( 'a' ); //结果 a: (refcount=1, is_ref=0)=array ( 'life' => (refcount=1, is_ref=0)='life' )
배열 자체를 이 배열의 요소로 추가하면 상황이 흥미로워집니다
위와 마찬가지로 변수에 대해 unset을 호출하면 해당 기호와 해당 변수가 가리키는 변수가 삭제됩니다. 컨테이너의 참조 수도 1
<?php $a = array( 'one' ); $a[] = &$a; xdebug_debug_zval( 'a' ); //结果 a: (refcount=2, is_ref=1)=array ( 0 => (refcount=1, is_ref=0)='one', 1 => (refcount=2, is_ref=1)=... )
이 구조를 가리키는 범위에 더 이상 기호가 없지만(즉, 변수 컨테이너), 배열 요소 "1"은 여전히 배열 자체를 가리키므로 이 컨테이너를 지울 수 없습니다.
이를 가리키는 다른 기호가 없기 때문에 사용자는 이 구조를 지울 수 없으며 이로 인해 메모리 누수가 발생합니다.
다행히도 php는 스크립트 실행이 끝나면 이 데이터 구조를 지웁니다. 하지만 php가 이를 지우기 전에 많은 메모리가 소모됩니다.
위 상황이 한두번만 일어나도 괜찮지만, 메모리 누수가 수천, 심지어 수십만 번 발생한다면 이는 분명히 큰 문제입니다
PHP가 이전에 사용했던 것과 같습니다. 메모리 메커니즘은 순환 참조 메모리 누수를 처리할 수 없습니다
이 메모리 누수 문제를 처리하기 위해 PHP 5.3.0에서 동기화 알고리즘이 사용되었습니다.
참조 횟수가 증가하면 계속 사용되며 더 이상 사용되지 않습니다. 쓰레기통에.
참조 카운트가 0으로 줄어들면 변수 컨테이너가 지워집니다(무료)
즉, 참조 카운트가 0이 아닌 값으로 줄어들 때만 가비지 사이클이 발생합니다
가비지에서 순환, 참조를 확인하여 카운트가 1만큼 감소했는지 확인하고 어떤 변수 컨테이너의 참조 시간이 0인지 확인하여 어떤 부분이 가비지인지 알아보세요
모든 참조를 확인하지 않으려면 카운트하면 쓰레기 주기가 줄어들 수 있습니다
이 알고리즘은 가능한 모든 루트(가능한 루트는 zval 변수 컨테이너)를 루트 버퍼(보라색으로 표시, 의심스러운 쓰레기라고 함)에 넣습니다. 따라서 가능한 모든 쓰레기 루트가 동시에 보장될 수 있습니다(가능한 쓰레기 루트)는 한 번만 나타납니다. 버퍼에서. 가비지 수집은 루트 버퍼가 가득 찬 경우에만 버퍼 내의 모든 다른 변수 컨테이너에서 수행됩니다. 위 이미지의 A단계를 살펴보세요.
B단계에서 각 보라색 변수 삭제를 시뮬레이션합니다. 삭제를 시뮬레이션할 때 보라색이 아닌 일반 변수의 참조 카운트가 "1"만큼 줄어들 수 있습니다. 일반 변수의 참조 카운트가 0이 되면 이 일반 변수의 삭제를 다시 시뮬레이션합니다. 각 변수는 한 번만 시뮬레이션 삭제될 수 있으며 시뮬레이션 삭제 후에는 회색으로 표시됩니다
C 단계에서 시뮬레이션은 각 보라색 변수를 복원합니다. 복구는 조건부입니다. 변수의 참조 횟수가 0보다 크면 복구되도록 시뮬레이션됩니다. 마찬가지로 각 변수는 한 번만 복원할 수 있습니다. 복원 후에는 기본적으로 B단계의 역동작입니다. 이런 식으로 복구할 수 없는 나머지 블루 노드 더미는 삭제해야 하는 블루 노드입니다. D 단계에서 이를 탐색하여 삭제합니다
성능에 영향을 미치는 두 가지 주요 영역이 있습니다
부분 1 하나는 메모리 공간 절약입니다
다른 하나는 가비지 수집 메커니즘이 누출된 메모리를 해제하는 데 걸리는 시간의 증가입니다
PHP의 가비지 수집 메커니즘은 오직 사실입니다 사이클 재활용 알고리즘에서는 런타임 동안 시간 소모가 증가합니다. 그러나 일반(더 작은) 스크립트에서는 성능에 전혀 영향을 미치지 않아야 합니다.
그러나 재활용 메커니즘이 실행되는 일반 스크립트의 경우 메모리 절약을 통해 서버에서 더 많은 스크립트를 동시에 실행할 수 있습니다. 사용된 총 메모리가 상한에 도달하지 않았기 때문입니다.
이 이점은 장기 실행 테스트 모음이나 데몬 스크립트와 같은 장기 실행 스크립트에서 특히 분명합니다.
(추천 튜토리얼: PHP 비디오 튜토리얼)
위 내용은 PHP의 가비지 수집 메커니즘에 대해 자세히 알아보세요.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!