>백엔드 개발 >PHP 문제 >PHP에서 참조 카운팅은 무엇을 의미합니까?

PHP에서 참조 카운팅은 무엇을 의미합니까?

醉折花枝作酒筹
醉折花枝作酒筹앞으로
2021-05-08 17:31:401811검색

이 글에서는 PHP의 참조 카운팅에 대해 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제