PHP 할당 의 내 부 는 어떻게 달 리 는 지 에 대한 자세 한 설명 입 니 다.

머리말
PHP 에서 하나의 변수 가 할당 되 었 습 니 다.내 부 는 도대체 어떤 논리 적 판단 을 거 쳤 습 니까?
PHP 는 커 널 에서 zval 이라는 구조 체 를 통 해 변 수 를 저장 합 니 다.이 정 의 는 Zend/zend.h 파일 에 있 습 니 다.

struct _zval_struct {zvalue_value value; /*      */zend_uint refcount__gc;zend_uchar type; /*           */zend_uchar is_ref__gc;};typedef struct _zval_struct zval;// Zend/zend_types.h    :typedef unsigned int zend_uint;typedef unsigned char zend_uchar;
xdebug 의 xdebug 사용 하기debug_zval 함 수 는 변수의 refcount,is 를 출력 할 수 있 습 니 다.ref 의 값.

$a = 'Hello World';$b = $a;
이상 의 내용 은 내부 핵 에서 어떻게 집행 합 니까?

zval *helloval;MAKE_STD_ZVAL(helloval);ZVAL_STRING(helloval, "Hello World", 1);zend_hash_add(EG(active_symbol_table), "a", sizeof("a"),&helloval, sizeof(zval*), NULL);ZVAL_ADDREF(helloval); //     ,        helloval    refcountzend_hash_add(EG(active_symbol_table), "b", sizeof("b"),&helloval, sizeof(zval*), NULL);
변 수 를 할당 할 때 두 변 수 는 같은 주소 공간 을 가리 키 는 것 을 알 수 있 습 니 다.그러면 문제 가 생 겼 습 니 다.같은 주소 공간 을 가리 키 면 수정 a 가 아니 라 b 도 달라 집 니 다.이것 은 php 의 작성 시 복제 메커니즘 과 관련된다.위 코드 는 다음 행동$b='123'의 판단 과정 이 다음 과 같 습 니 다.
  • 이 변수의 zval 부분의 refcount 가 2 보다 작 으 면 다른 변수 가 사용 되 지 않 는 다 는 뜻 이 므 로 이 값 을
  • 으로 직접 수정 합 니 다.
  • 그렇지 않 으 면 zval 의 값 을 복사 하여 원래 zval 의 refcount 값 을 감소 하고 새로운 zval 의 refcount 를 초기 화 하 며 새로 복 제 된 zval
  • 을 수정 합 니 다.
    단순 변수
    우선 할당 을 참조 한 후 일반 할당
    
    var_dump(memory_get_usage());$a = '1234567890';xdebug_debug_zval('a');var_dump(memory_get_usage());$b = &$a;xdebug_debug_zval('a','b');var_dump(memory_get_usage());$c = $a;xdebug_debug_zval('a','b','c');var_dump(memory_get_usage());$a = '1234567890';var_dump(memory_get_usage());$b = &$a;var_dump(memory_get_usage());$c = $a;
    출력 내용 은 다음 과 같 습 니 다:
    int(121672)
    a: (refcount=1, is_ref=0)='1234567890'
    int(121776)
    a: (refcount=2, is_ref=1)='1234567890'
    b: (refcount=2, is_ref=1)='1234567890'
    int(121824)
    a: (refcount=2, is_ref=1)='1234567890'
    b: (refcount=2, is_ref=1)='1234567890'
    c: (refcount=1, is_ref=0)='1234567890'
    int(121928)
    $a 할당,104 byte 공간,변수 a refcount=1,isref=0
    $b 할당,48byte 공간,변수 a refcount=2,isref=1。48byte 는 기호 표 점용,a,b 는 같은 주소 공간 을 실행 합 니 다.
    $c 할당,104 byte 공간 을 열 었 습 니 다.a,b 는 인용 이기 때문에 c 할당 시 새로운 공간 을 열 고 a zval 내용 을 복사 하 며 refcount,is 를 초기 화 합 니 다.ref,그래서 a 의 refcount 는 변 하지 않 습 니 다.c 의 refcount=1
    일반 할당 후 할당 참조
    
    var_dump(memory_get_usage());$a = '1234567890';xdebug_debug_zval('a');var_dump(memory_get_usage());$b = $a;xdebug_debug_zval('a','b');var_dump(memory_get_usage());$c = &$a;xdebug_debug_zval('a','b','c');var_dump(memory_get_usage());
    출력 내용 은 다음 과 같 습 니 다:
    int(121672)
    a: (refcount=1, is_ref=0)='1234567890'
    int(121776)
    a: (refcount=2, is_ref=0)='1234567890'
    b: (refcount=2, is_ref=0)='1234567890'
    int(121824)
    a: (refcount=2, is_ref=1)='1234567890'
    b: (refcount=1, is_ref=0)='1234567890'
    c: (refcount=2, is_ref=1)='1234567890'
    int(121928)
    $a 할당,104 byte 공간,변수 a refcount=1,isref=0
    $b 할당,48byte 공간,변수 a refcount=2,isref=1。48byte 는 기호 표 점용,a,b 는 같은 주소 공간 을 가리킨다
    $c 할당,104 byte 공간 을 열 었 습 니 다.a,c 는 인용 이기 때문에 b 와 격 리 되 어야 하기 때문에 기 존의 zval 을 할당 하고 zval 을 초기 화 하 며 a,c 를 새로 복 제 된 zval 을 가리 키 는 동시에 기 존의 zval refcount-1 을 가 리 킵 니 다.
    배열
    
    $arr = [0=>'one'];
    xdebug_debug_zval('arr');
    $arr[1] = $arr;
    
    xdebug_debug_zval('arr');
    
    $arr[2] = $arr;
    xdebug_debug_zval('arr');
    unset($arr[1]);
    xdebug_debug_zval('arr');
    unset($arr[2]);
    xdebug_debug_zval('arr');
    출력 내용 은 다음 과 같 습 니 다:
    arr: (refcount=1, is_ref=0)=array ( 0 => (refcount=1, is_ref=0)='one')
    )
    arr: (refcount=1, is_ref=0)=array (
    0 => (refcount=2, is_ref=0)='one',
    1 => (refcount=1, is_ref=0)=array (
    0 => (refcount=2, is_ref=0)='one'
    )
    )
    arr: (refcount=1, is_ref=0)=array (
    0 => (refcount=3, is_ref=0)='one',
    1 => (refcount=2, is_ref=0)=array (
    0 => (refcount=3, is_ref=0)='one'),
    2 => (refcount=1, is_ref=0)=array (
    0 => (refcount=3, is_ref=0)='one',
    1 => (refcount=2, is_ref=0)=array (...)
    )
    )
    arr: (refcount=1, is_ref=0)=array (
    0 => (refcount=3, is_ref=0)='one',
    2 => (refcount=1, is_ref=0)=array (
    0 => (refcount=3, is_ref=0)='one',
    1 => (refcount=1, is_ref=0)=array (...)
    )
    )
    arr: (refcount=1, is_ref=0)=array (
    0 => (refcount=1, is_ref=0)='one'
    )
    $arr = [0=>'one'];xdebug_debug_zval('arr');$arr[1] = &$arr;xdebug_debug_zval('arr');$arr[2] = $arr;xdebug_debug_zval('arr');unset($arr[1]);xdebug_debug_zval('arr');unset($arr[2]);xdebug_debug_zval('arr');
    출력 내용 은 다음 과 같 습 니 다:
    arr: (refcount=1, is_ref=0)=array (
    0 => (refcount=1, is_ref=0)='one'
    )
    arr: (refcount=2, is_ref=1)=array (
    0 => (refcount=1, is_ref=0)='one',
    1 => (refcount=2, is_ref=1)=...
    )
    arr: (refcount=3, is_ref=1)=array (
    0 => (refcount=2, is_ref=0)='one',
    1 => (refcount=3, is_ref=1)=...,
    2 => (refcount=2, is_ref=0)=array (
    0 => (refcount=2, is_ref=0)='one',
    1 => (refcount=3, is_ref=1)=...,
    2 => (refcount=2, is_ref=0)=...)
    )
    arr: (refcount=2, is_ref=1)=array (
    0 => (refcount=2, is_ref=0)='one',
    2 => (refcount=2, is_ref=0)=array (
    0 => (refcount=2, is_ref=0)='one',
    1 => (refcount=2, is_ref=1)=...,
    2 => (refcount=2, is_ref=0)=...)
    )
    arr: (refcount=2, is_ref=1)=array (
    0 => (refcount=2, is_ref=0)='one'
    )
    상단 테스트 코드 는 매우 비슷 하 며,차 이 는 arr[1]참조 할당 여부 에 만 있 습 니 다.
    arr[1]비 인용 할당 의 경우 arr[0]의 refcount=할당 횟수+1,두 번 unset 을 실행 한 후 arr,arr[0]의 refcount 는 모두 정 의 를 시작 할 때 와 일치 합 니 다.arr[1]할당 을 참조 하 는 경우 arr[0]의 refcount=비 인용 할당 횟수+1,unset 를 두 번 실행 한 후 arr,arr[0]의 refcount 는 정 의 된 값 으로 돌아 갈 수 없습니다.
    주요 원인 은 arr[1]가 할당 을 인용 하여 재 귀 작업 을 구성 하 는 데 있다.하지만 이 refcount 에 대해 서 는 정말 잘 모 르 겠 어 요.arr[2]할당 이 없 을 때 unset 을 실행 하면 arr refcount 는 1 로 돌아 갈 수 있 습 니 다.아래 의 이 그림 에서 내부 귀속 인용 을 더욱 뚜렷하게 볼 수 있다

    위 와 같은 상황 이 발생 하면 refcount 는=1 이 어야 하 는데 실제 위 에 1 로 설정 되 지 않 으 면 메모리 누 출 이 발생 합 니 다.위의 코드 는 100 회 순환 하여 실행 되 었 고 메모 리 는 처음에 121096 에서 169224 로 올 라 갔 으 며 메모리 사용량 은 5k 올 랐 다.
    대상
    
    $user = new User();
     $m = $user;
     $user->user ='';
     $user->name = 'sdfsdfs';
     xdebug_debug_zval('user','m');
    이상 내용 출력
    (refcount=2, is_ref=0)=class User {
    public $name = (refcount=1, is_ref=0)='sdfsdfs';
    public $model = (refcount=1, is_ref=0)=NULL;
    public $user = (refcount=1, is_ref=0)=''
    }
    m: (refcount=2, is_ref=0)=class User {
    public $name = (refcount=1, is_ref=0)='sdfsdfs';
    public $model = (refcount=1, is_ref=0)=NULL;
    public $user = (refcount=1, is_ref=0)=''
    }
    xdebug 가 내 놓 은 isref=0。refcount 는 일반 변수 와 계속 합 니 다.그러나 클래스 의 할당 은 인용 할당 입 니 다.
    
    $user = new User();
     $user->user = $user;
     $user->name = 'sdfsdfs';
     xdebug_debug_zval('user');
     unset($user);
    위 내용 출력:
    user: (refcount=2, is_ref=0)=class User { public $name = (refcount=1, is_ref=0)='sdfsdfs'; public $user = (refcount=2, is_ref=0)=... }
    여기 서 클래스 의 할당 은 할당 을 참조 하 는 것 이기 때문에 색인 도 재 귀 작업 을 구성 합 니 다.그러면 배열 과 마찬가지 로 메모리 누 출 이 발생 할 수 있 습 니 다.다음 코드 개 자체 100 회
    
    $user = new User();
     $user->user = $user;
     $user->name = 'sdfsdfs';
     xdebug_debug_zval('user');
     unset($user);
    $user = new User();
     $user->user = new Order();
     $user->name = 'sdfsdfs';
     xdebug_debug_zval('user');
     unset($user);
    1 단 코드 전후 메모리 차 1408 byte.2 단 코드 차 208 byte.
    총결산
    이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

    좋은 웹페이지 즐겨찾기