PHP5의 쓰레기 수집 메커니즘 기본 원칙

개념

쓰레기 수집 메커니즘은 자동으로 프로그램의 할당 된 메모리 블록이 더 이상 사용되지 해제하지 않습니다, 동적으로 할당 된 메모리 방식이다.

쓰레기 수집 메커니즘 허용 프로그래머가 비즈니스 로직에 더 많은 에너지를 넣어 메모리 할당 프로그램에 대해 지나치게 우려하지.

개념과 관련, 메모리 누수는 프로그램이 메모리의 낭비의 결과로, 사용에 더 이상 메모리를 해제하는 데 실패 없다는 것을 의미한다.

그래서 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는기구를 도입하기 시작)

참고 자료

자세한 학습의 고급 PHP 쓰레기 수집 메커니즘

PHP의 가비지 수집 메커니즘 기본 원칙

참조 카운팅 기본

추천

출처www.cnblogs.com/wuliaojava/p/11759806.html