이 글에서는 PHP의 참조 카운팅에 대해 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.
PHP의 데이터 구조에서 참조 카운팅은 각 변수의 유형과 값을 저장하는 것 외에도 두 가지 추가 내용을 저장합니다. 다른 하나는 인용 횟수입니다. 왜 콘텐츠를 두 개 더 저장해야 하나요? 물론 GC(가비지 수집)용입니다.
즉, 참조 수가 0이 되면 이 변수는 더 이상 사용되지 않으며 GC를 통해 재활용하여 점유된 메모리 자원을 해제할 수 있습니다.
어떤 프로그램도 메모리 자원을 무한정 점유할 수 없습니다. 과도한 메모리 사용은 종종 심각한 문제, 즉 메모리 누수를 초래합니다. GC는 사용하지 않고도 자동으로 메모리 파괴를 완료하는 PHP의 하위 계층입니다. C. 수동으로 해제해야 합니다.
xdebug 확장을 설치한 다음 xdebug_debug_zval() 함수를 사용하여 지정된 메모리의 자세한 정보를 확인해야 합니다. 예:
$a = "I am a String"; xdebug_debug_zval('a'); // a: (refcount=1, is_ref=0)='I am a String'
위에서 볼 수 있듯이 이 $a 변수의 내용은 다음과 같습니다. 나는 이 문자열과 같은 문자열입니다. 괄호 안의 refcount는 참조 개수이고, is_ref는 변수 참조 여부를 나타냅니다. 변수 할당을 통해 이 두 매개변수가 어떻게 변경되는지 살펴보겠습니다.
$b = $a; xdebug_debug_zval('a'); // a: (refcount=1, is_ref=0)='I am a String' $b = &$a; xdebug_debug_zval('a'); // a: (refcount=2, is_ref=1)='I am a String'
일반 할당을 수행하면 refcount와 is_ref에는 변화가 없지만 참조 할당을 수행하면 refcount가 2가 되고 is_ref가 1이 되는 것을 볼 수 있습니다. 이는 현재 $a 변수가 참조로 할당되고 해당 메모리 기호 테이블이 두 변수 $a 및 $b를 제공한다는 의미입니다.
$c = &$a; xdebug_debug_zval('a'); // a: (refcount=3, is_ref=1)='I am a String' unset($c, $b); xdebug_debug_zval('a'); // a: (refcount=1, is_ref=1)='I am a String' $b = &$a; $c = &$a; $b = "I am a String new"; xdebug_debug_zval('a'); // a: (refcount=3, is_ref=1)='I am a String new' unset($a); xdebug_debug_zval('a'); // a: no such symbol
$c에 참조 할당을 계속 추가하면 refcount가 계속 증가하는 것을 볼 수 있습니다. 그런 다음 $b 및 $c를 설정 해제한 후 refcount는 1로 반환됩니다. 그러나 is_ref는 여전히 1이라는 점에 유의해야 합니다. 즉, 이 변수가 참조된 경우 참조된 변수가 짝수인 경우에도 is_ref는 1이 됩니다. 설정되지 않은 경우 값은 변경되지 않습니다.
마지막으로 $a 설정을 해제하면 표시되는 메시지에 그런 기호가 없습니다. 현재 변수는 삭제되었으며 더 이상 사용할 수 있는 기호 참조가 아닙니다. (PHP의 변수는 실제 메모리 주소가 아닌 메모리 기호 테이블에 해당합니다.)
일반 유형 변수와 마찬가지로 객체 변수도 동일한 계산 규칙을 사용합니다.
// 对象引用计数 class A{ } $objA = new A(); xdebug_debug_zval('objA'); // objA: (refcount=1, is_ref=0)=class A { } $objB = $objA; xdebug_debug_zval('objA'); // objA: (refcount=2, is_ref=0)=class A { } $objC = $objA; xdebug_debug_zval('objA'); // objA: (refcount=3, is_ref=0)=class A { } unset($objB); class C{ } $objC = new C; xdebug_debug_zval('objA'); // objA: (refcount=1, is_ref=0)=class A { }
그러나 여기서는 객체의 기호 테이블이 설정된 연결이라는 점에 유의해야 합니다. 즉, $objC를 NULL로 다시 인스턴스화하거나 수정해도 $objA의 내용에는 영향을 미치지 않습니다. 이전 객체 할당이 PHP에서 참조인가요? 기사에 설명되어 있습니다. 객체에 대한 일반적인 할당 작업은 참조 유형의 기호 테이블 할당이기도 하므로 & 기호를 추가할 필요가 없습니다.
// 数组引用计数 $arrA = [ 'a'=>1, 'b'=>2, ]; xdebug_debug_zval('arrA'); // arrA: (refcount=2, is_ref=0)=array ( // 'a' => (refcount=0, is_ref=0)=1, // 'b' => (refcount=0, is_ref=0)=2 // ) $arrB = $arrA; $arrC = $arrA; xdebug_debug_zval('arrA'); // arrA: (refcount=4, is_ref=0)=array ( // 'a' => (refcount=0, is_ref=0)=1, // 'b' => (refcount=0, is_ref=0)=2 // ) unset($arrB); $arrC = ['c'=>3]; xdebug_debug_zval('arrA'); // arrA: (refcount=2, is_ref=0)=array ( // 'a' => (refcount=0, is_ref=0)=1, // 'b' => (refcount=0, is_ref=0)=2 // ) // 添加一个已经存在的元素 $arrA['c'] = &$arrA['a']; xdebug_debug_zval('arrA'); // arrA: (refcount=1, is_ref=0)=array ( // 'a' => (refcount=2, is_ref=1)=1, // 'b' => (refcount=0, is_ref=0)=2, // 'c' => (refcount=2, is_ref=1)=1 // )
배열을 디버깅할 때 두 가지 흥미로운 점을 발견하게 됩니다.
먼저, 배열 내부의 각 요소에는 고유한 별도의 참조 카운트가 있습니다. 이는 또한 이해하기 쉽습니다. 각 배열 요소는 별도의 변수로 간주될 수 있지만 배열은 이러한 변수의 해시 집합입니다. 객체에 멤버 변수가 있으면 동일한 효과가 발생합니다. 배열의 요소가 &에 의해 다른 변수에 할당되면 전체 배열의 참조 개수에 영향을 주지 않고 이 요소의 참조 개수가 증가됩니다.
두 번째, 배열의 기본 참조 횟수는 2입니다. 실제로 이는 PHP7 이후에 새로 추가된 기능으로, 배열을 정의하고 초기화하면 불변 배열(immutable array)로 변환됩니다. 일반 배열과 구별하기 위해 이 배열의 참조 횟수는 2부터 시작합니다. 이 배열의 요소를 수정하면 배열이 다시 일반 배열로 변경됩니다. 즉, refcount가 다시 1로 변경됩니다. 이것을 직접 시도해 볼 수 있습니다. 공식적인 설명은 효율성을 위한 것입니다. PHP7의 소스 코드를 자세히 살펴봐야 할 수도 있습니다.
사실 PHP는 이미 하위 수준의 GC 메커니즘을 지원했기 때문에 변수의 파괴 및 해제에 대해 너무 걱정할 필요가 없습니다. 그러나 비용을 지불해야 합니다. 객체나 배열의 요소가 자신에게 값을 할당할 수 있다는 사실에 주의하세요. 즉, 요소 자체에 대한 참조를 할당하는 것은 순환 참조가 됩니다. 그러면 이 객체는 기본적으로 GC에 의해 자동으로 파괴될 가능성이 없습니다.
// 对象循环引用 class D{ public $d; } $d = new D; $d->d = $d; xdebug_debug_zval('d'); // d: (refcount=2, is_ref=0)=class D { // public $d = (refcount=2, is_ref=0)=... // } // 数组循环引用 $arrA['arrA'] = &$arrA; xdebug_debug_zval('arrA'); // arrA: (refcount=2, is_ref=1)=array ( // 'a' => (refcount=0, is_ref=0)=1, // 'b' => (refcount=0, is_ref=0)=2, // 'arrA' => (refcount=2, is_ref=1)=... // )
객체이든 배열이든, 인쇄 및 디버깅 중에...와 같은 줄임표가 나타나면 프로그램에 순환 참조가 있는 것입니다. PHP의 객체 복사에 관한 이전 기사에서 우리는 이 순환 참조 문제에 대해서도 이야기했습니다. 따라서 이 문제는 일상적인 개발에서 항상 주의해야 할 문제입니다.
추천 학습: php 비디오 튜토리얼
위 내용은 PHP에서 참조 카운팅은 무엇을 의미합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!