개념
쓰레기 수집 메커니즘은 자동으로 프로그램의 할당 된 메모리 블록이 더 이상 사용되지 해제하지 않습니다, 동적으로 할당 된 메모리 방식이다.
쓰레기 수집 메커니즘 허용 프로그래머가 비즈니스 로직에 더 많은 에너지를 넣어 메모리 할당 프로그램에 대해 지나치게 우려하지.개념과 관련, 메모리 누수는 프로그램이 메모리의 낭비의 결과로, 사용에 더 이상 메모리를 해제하는 데 실패 없다는 것을 의미한다.
그래서 PHP 가비지 수집 메커니즘은 그것을 달성하는 방법은?
내부 저장 구조 PHP 변수
처음에는 이해 할 필요가있다 기초 가비지 컬렉터의 내용의 원리에 대한 이해를 촉진하기 위하여는,.
PHP 모든 유형 의 변수는 아래쪽에있는 zval 구조 의 형태로 구현 (소스 코드 파일 젠드 / zend.h)
소스 루트 디렉토리 검색
grep -rin --color --include=*.h --include=*.c _zval_struct *
struct _zval_struct {
/* Variable information */
zvalue_value value; /* 变量value值 */
zend_uint refcount__gc; /* 引用计数内存中使用次数,为0删除该变量 */
zend_uchar type; /* 变量类型 */
zend_uchar is_ref__gc; /* 区分是否是引用变量,是引用为1,否则为0 */
};
참고 : 새로운 쓰레기 수집 메커니즘, 즉 전혀 소개가 없기 때문에 위의 zval 구조 php5.3 전에, php5.3 버전 이후의 구조 GC는 , 그래서 이름이 없다 _gc
,하지만 인해 성능 문제에 php7 버전 이후 그래서 여기 zval 구조를 다시 작성 더 이상 표시되지 않습니다.
참조 계산 원리
변수 컨테이너
각각라는 PHP 변수에 저장 zval 변수 컨테이너입니다. 가변 컨테이너를 생성 할 때, 상기 용기 변수 ref_count 초기 값 (1)은, 각 변수 뒤에 사용될 ref_count + 1 . 당신이 변수를 삭제하면 ( 설정 해제는 () ), 다음 변수 컨테이너를 가리키는 ref_count - 1 .
비 배열 및 목적 변수
변수에 할당마다 상수는 것 변수 컨테이너를
예를 들면 :
$a = 'new string';
xdebug_debug_zval('a');
결과가 출력됩니다 :
a:(refcount=1, is_ref=0),string 'new string' (length=10)
배열 및 목적 변수
가변 상수 값마다 것이다 소자 +1의 개수 zval을
예를 들면 :
$b = [
'name' => 'new string',
'number' => 12
];
xdebug_debug_zval('b');
결과가 출력됩니다 :
b:
(refcount=1, is_ref=0),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
'number' => (refcount=1, is_ref=0),int 12
할당 원칙
기록 중 복사 원칙
설계 PHP는 두 변수의 동일한 값에 대한 변수의 할당은 메모리를 공유하도록 메모리를 절약하기 위해, 즉 될 것이다 전역 심볼 테이블 의 B 변수 내에 가변 포인터 소수점 변수 의 점 동일한 구조를 zval 하지만, 변수 변경, 따라서 가변 컨테이너 메모리 복사 발생 변경하는 것 zval 구조라고 한 경우에만 복사 (copy-on-write) 원리 .
원칙적으로 복사 (copy-on-write) 트리거 타이밍을 :
변수 수정 PHP 때 참조 카운트> 1 용기가 변화 메모리 복사를 수행 할 경우 변수가 발견
예를 들면 :
// 创建一个变量容器,变量 a 指向给变量容器,a 的 ref_count 为 1
$a = ['name' => 'string','number' => 3];
// 变量 b 也指向变量 a 指向的变量容器,a 和 b 的 ref_count 为 2
$b = $a;
xdebug_debug_zval('a', 'b');
echo '<hr/>'
// 变量 b 的其中一个元素发生改变,此时会复制出一个新的变量容器,变量 b 重新指向新的变量容器,a 和 b 的ref_count 变成 1
$b['name'] = 'new string';
xdebug_debug_zval('a', 'b');
출력 결과 :
a:(refcount=2, is_ref=0),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'string' (length=6)
'number' => (refcount=1, is_ref=0),int 3
b:(refcount=2, is_ref=0),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'string' (length=6)
'number' => (refcount=1, is_ref=0),int 3
________________________________________________________________________________________
a:(refcount=1, is_ref=0),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'string' (length=6)
'number' => (refcount=2, is_ref=0),int 3
b:(refcount=1, is_ref=0),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
'number' => (refcount=2, is_ref=0),int 3
작성시 원칙적으로 변경
그는 일반 과제의 경우, 다음 과제는이를 참조 것이라고?
첫 번째 그림의 방법으로
$a = ['name' => 'string','number' => 3];
$b = &$a;
xdebug_debug_zval("a", "b");
결과 출력
a:(refcount=2, is_ref=1),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'string' (length=6)
'number' => (refcount=1, is_ref=0),int 3
b:(refcount=2, is_ref=1),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'string' (length=6)
'number' => (refcount=1, is_ref=0),int 3
이 시점에서, 우리는 변수 A 및 B 참조 카운트 한두 발견하지만, 1 is_ref된다 변수 B에 할당 된 참조 변수는 변수가 원래 용기 내에 수정 되었으면 is_ref해질 것이다 때문입니다 1을 참조 카운트 + 1
기준에 근거하여 그 임무가 그것의 변수를 변경 한 경우?
$a = ['name' => 'string','number' => 3];
$b = &$a;
$b['name'] = "new string";
xdebug_debug_zval("a", "b");
출력 결과 :
a:(refcount=2, is_ref=1),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
'number' => (refcount=1, is_ref=0),int 3
b:(refcount=2, is_ref=1),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
'number' => (refcount=1, is_ref=0),int 3
트리거가 있기 때문에 놀라운 것은, 사실의 변수 변수 B와의 값의 변화가 있었다, 무슨 일이 있었 쓰기 원칙을 변경 .
기록 인 원리로 변경 트리거 타이밍 :
가변 용기 1 is_ref 변수 is_ref 우선 검사 용기가 할당되기 전에 것은 복사 (copy-on-write)를 수행하지만, 원래의 변수에 기초하여 상기 컨테이너의 내용을 수정하지 않은 경우, 1과 같다; 다른 변수는 변수 용기 (1)에 할당 is_ref 경우, 그 즉시 트리거 변화 기록 원리
이제 위의 예제를 결합, 그것은 같은 것?
$a = ['name' => 'string','number' => 3];
$b = $a;
$c = &$a;
xdebug_debug_zval("a", "b", "c");
출력 결과 :
구현 과정 :
제 행 수행 : 참조 카운트 변수 컨테이너
참조 카운트 변수 용기 (2), 변수 A 및 B 공유 같은 변수 용기 : 제 2 로우 수행
세 번째 줄의 구현 : 변화가 발생하는 경우 트리거, 상기 변수 (C)이 시간 가변 컨테이너 참조 카운트> 1에 할당 된 변수를 참조하는 복사 (copy-on-write)을 , 변수 (A)와 (B)의 분리는, 그 변수에 대한 참조에 할당 C 변수 변수 is_rel 컨테이너는 1이되고, 2 참조 카운트된다.
0 레퍼런스 카운트
컨테이너가 가변되는 경우 ref_count가 가변 컨테이너가 메모리 복구를 달성 파손됨을 나타내는 0으로 계산.
이것은이다 PHP 5.3 버전으로 가비지 컬렉션의 전에.
예를 들면 :
$a = "new string";
$b = $a;
xdebug_debug_zval('a');
unset($b); // 删除了符号表中的变量名 b,同时它指向的变量容器 ref_count -1
xdebug_debug_zval('a');
xdebug_debug_zval('b');
출력 결과 :
a:(refcount=2, is_ref=0),string 'new string' (length=10)
a:(refcount=1, is_ref=0),string 'new string' (length=10)
b: no such symbol
순환 참조 메모리로 인한 누출
우리는이 어레이 또는 객체의 요소로서 배열이나 객체를 추가하면 이번에는 변수 기호 (해제)을 삭제 한 경우, 및이 변수 용기는 삭제되지 않는다. 때문에 그 자식 요소 중 여전히 변수 컨테이너를 가리키는하지만 때문에 변수 컨테이너를 가리키는 흔적없이 모든 범위이 변수 컨테이너를 삭제하는 사용자 그래서 아무 방법의 결과는 스크립트 실행 수동 분명이 변수 컨테이너가 끝날 때까지 메모리 누수로 이어질 것 .
예를 들어 요소로 배열에 추가하는 방법
$a = array( 'one' );
$a[] = &$a;
xdebug_debug_zval( 'a' );
출력 :
a:
(refcount=2, is_ref=1),
array (size=2)
0 => (refcount=1, is_ref=0),string 'one' (length=3)
1 => (refcount=2, is_ref=1),&array<
아이콘 :
배열 변수 볼 A는 또한 어레이의 두 번째 요소 인 "1"로 가변 컨테이너가 가리키는 참조 카운트가 있다 (2) . 위의 출력 및 배열 < 수단은, 원래의 배열을 향하는된다.
그냥 기호를 제거 할 변수 해제에 대한 호출 및 가리키는 변수 컨테이너 하나에 의해 감소 인용 횟수와 같은. 우리는 상기 코드 변수 실행중인 경우에 따라서, 해제 호를 다음 변수 가변 배열 요소 컨테이너는 "1"의 인용은 1 감산하도록 지시 (2)가 된다 (1) . 다음의 예를 예시 할 수있다 :
unset($a);
아이콘 :
위의 상황은 아무것도 아래로 한 번 또는 두 번 발생하지만 경우 경우 수천 번, 분명히 큰 문제가 메모리 누수가 발생 번, 수천의 수백. 이러한 문제는 종종에 요청 데몬 (deamons) 기본적으로 끝나지 않는다거나 큰 단위 테스트 스위트 (세트)로, 장기 실행 스크립트에서 발생한다.
새로운 가비지 컬렉션
PHP 5.3 버전 이후에 도입 루트 버퍼링 메커니즘 , 루트 버퍼의 기본 설정으로 지정된 zval 즉 PHP가 시작됩니다 (기본값 10000), PHP의 존재 때이 발견 된 순환 참조가 zval는, 버퍼에 뿌리를 넣을 때, 때 루트 버퍼 (기본값은 10000) 수 지정된 구성 파일에 도달하면, 순환 참조로 인한 메모리 누수를 해결하기 위해, 가비지 컬렉션을 수행합니다.
가비지 수집 알고리즘
루트 버퍼가 가득 할 때마다, PHP는 선박 이송이 할 수있는 모든 변수의 루트 버퍼 것입니다 삭제 시뮬레이션을 한 다음 복구를 시뮬레이션 . 그러나, PHP만을 시뮬레이션 후에 삭제 될 가변 컨테이너 복구 참조 카운트> 0 , 일절 복구하지 참조 카운트 = 0의 쓰레기 .
쓰레기의 기준으로 인정
레퍼런스 카운트가 용기 변수가 클리어 제로 (무료로), 스팸이 아닌로 감소되는 경우 (1),
(2) 기준은 더 감소 zval 경우, 카운트는 그 것이다 쓰레기로 사이클이 0보다 크다. 다음에, 기준 계수 횟수가 1만큼 감소 여부에 의해 쓰레기의 기간이며, 여기서 용기 검사 기준 변수 제로 부품 쓰레기되는 알 수있다.
개요
가비지 컬렉션 :
참조 카운팅 메커니즘을 기반 PHP 1 (이전에는기구 PHP5.3)
2 원형 PHP 루트 투입 할 zval 참조를 찾을가 루트 완충 메카니즘 반면 버퍼 루트 번호 지정된 구성 파일 도달 버퍼, 가비지 순환 참조에 의한 메모리 누수를 해결하기 위해 수집된다 (php5.3는기구를 도입하기 시작)