PHP 할당 의 내 부 는 어떻게 달 리 는 지 에 대한 자세 한 설명 입 니 다.
9295 단어 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'의 판단 과정 이 다음 과 같 습 니 다.단순 변수
우선 할당 을 참조 한 후 일반 할당
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.총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Laravel - 변환된 유효성 검사 규칙으로 API 요청 제공동적 콘텐츠를 위해 API를 통해 Laravel CMS에 연결하는 모바일 앱(또는 웹사이트) 구축을 고려하십시오. 이제 앱은 CMS에서 번역된 콘텐츠를 받을 것으로 예상되는 다국어 앱이 될 수 있습니다. 일반적으로 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.