자세한 PHP 참조 수

6366 단어 PHP참조 개수

인용 계수


PHP의 데이터 구조에서 인용 계수는 모든 변수를 가리키며 그 유형과 값을 저장하는 것 외에 두 가지 내용을 추가로 저장한다. 하나는 현재 이 변수가 인용되었는지, 다른 하나는 인용된 횟수이다.왜 이런 두 가지 내용을 더 저장해야 합니까?당연히 쓰레기 수거(GC)를 위해서다.즉, 인용 횟수가 0일 때 이 변수는 더 이상 사용되지 않고 GC를 통해 회수하여 점용된 메모리 자원을 방출할 수 있다.어떤 프로그램도 메모리 자원을 무제한으로 점용해서는 안 된다. 너무 큰 메모리 점용은 종종 심각한 문제를 가져온다. 그것이 바로 메모리 유출이다. GC는 PHP 밑바닥이 자동으로 메모리를 없애는 것을 도와주고 C처럼 수동으로 free를 하지 않아도 된다.

인용 계수는 어떻게 보십니까?


xdebug 확장을 설치하고 xdebug_를 사용해야 합니다debug_zval () 함수는 지정된 메모리에 대한 자세한 정보를 볼 수 있습니다. 예를 들어 다음과 같습니다.

$a = "I am a String";
xdebug_debug_zval('a');
// a: (refcount=1, is_ref=0)='I am a String'
상기 내용에서 알 수 있듯이 이 $a 변수의 내용은 I am a String과 같은 문자열이다.괄호 안에 있는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 변수가 인용된 값에 서비스되고, 그의 메모리 기호표는 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가 계속 증가하는 것을 볼 수 있습니다.그리고 unset에서 c의 인용 값을 떨어뜨리면refcount가 계속 증가하는 것을 볼 수 있습니다.그리고 unset이 b와 $c를 떨어뜨린 후,refcount는 1로 회복되었지만, 이때 주의해야 할 것은,is_ref는 여전히 1입니다. 즉, 이 변수가 인용되었습니다, 이is_ref는 1이 됩니다. 인용된 변수가 unset에서 떨어졌어도 이 값은 변하지 않습니다.
마지막으로 우리는 unset에서 $a를 떨어뜨렸는데, 표시된 것은 no such symbol입니다.현재 변수가 삭제되었습니다. 사용할 수 있는 기호가 아닙니다.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로 수정하는 것은 objC를 다시 실례화하거나 NULL로 수정하는 데 영향을 주지 않으며 objA의 내용에 영향을 주지 않는다. 대상이 일반적인 값 부여 작업을 하는 것도 인용 유형의 기호표 값이기 때문에 우리는 & 기호를 추가할 필요가 없다.

수조의 인용 계수


//  
$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
// )
수조를 디버깅할 때, 우리는 비교적 재미있는 두 가지 일을 발견할 수 있다.
첫째, 그룹 내부의 모든 요소는 단독의 인용 계수가 있다.이것도 비교적 이해하기 쉽다. 모든 수조 원소는 하나의 단독 변수라고 볼 수 있지만, 수조는 바로 이 변수의 해시 집합이다.객체에 멤버 변수가 있는 경우에도 마찬가지입니다.수조 중의 어떤 원소가 & 인용에 의해 다른 변수에 부여되면 이 원소의refcount는 증가하여 전체 수조의 refcount에 영향을 주지 않습니다.
둘째, 기본적으로 올라온 refcount는 2입니다.사실 이것은 PHP7 이후의 새로운 특성입니다. 그룹을 정의하고 초기화하면 이 그룹을 변하지 않는 그룹(immutablearray)으로 바꿉니다.일반 그룹과 구분하기 위해 이 그룹의 refcount는 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)=...
// )
개체든 그룹이든 디버깅을 인쇄할 때 나타났습니다.이런 생략 번호가 있으면, 당신의 프로그램에 순환 인용이 나타납니다.그래서 이 문제는 우리가 일상 개발에서 항상 관심을 가져야 할 문제일 것이다.

총결산


인용 계수는 쓰레기 회수 메커니즘을 이해하는 전제 조건이며, 현대 언어에 유사한 쓰레기 회수 메커니즘이 있기 때문에 우리의 프로그래밍을 더욱 쉽고 안전하게 할 수 있다.그렇다면 일상적인 개발에는 이런 것들이 전혀 쓰이지 않는다고 누가 그래?배워서는 안 된다는 뜻은 아니다. 순환적으로 이 문제를 인용하는 것처럼 코드에 대량의 유사한 코드가 가득 차 있을 때 시스템이 붕괴되는 것은 조만간의 일이다. 그래서 이런 지식은 우리가 더 높은 프로그램으로 진급할 수 없거나 부족한 내용이다.
테스트 코드:github.com/zhangyue050…
이상은 PHP의 인용 계수에 대한 상세한 내용입니다. PHP의 인용 계수에 대한 더 많은 자료는 저희 다른 관련 글을 주목해 주십시오!

좋은 웹페이지 즐겨찾기