>  기사  >  백엔드 개발  >  PHP 스크립트의 메모리 관리 및 가비지 수집

PHP 스크립트의 메모리 관리 및 가비지 수집

不言
不言원래의
2018-05-30 09:57:411607검색

이 기사에서는 PHP 스크립트의 메모리 관리 및 가비지 수집에 대해 공유합니다. 필요한 친구가 참조할 수 있는 예제를 통해 PHP 스크립트의 메모리 관리 및 가비지 수집을 보여줍니다.

참조 할당

$a = 'apple';
$b = &$a;

위 코드에서는 변수 a에 문자열을 할당한 다음 변수 b에 a의 참조를 할당했습니다. 당연히 이때 가리키는 메모리는 다음과 같아야 합니다.

$a -> 'apple' <- $b

a와 b가 동일한 메모리 영역(변수 컨테이너)을 가리키고, var_dump($a, $b)</code를 통해 <code>를 얻습니다. > string(5) "apple" string(5) "apple" , 이는 예상된 결과입니다. var_dump($a, $b) 得到 string(5) "apple" string(5) "apple" ,这是我们预期的结果。


引用计数 与 unset( )

假如我想将 &#39;apple&#39; 这个字符串从内存中释放掉。我是这么做的:

unset($a);

但是通过再次打印 $a $b 两变量的信息,我得到了这样的结果:Notice: Undefined variable: astring(5) "apple" 。奇怪,$a $b 同时指向一块内存区域,又明明将$a释放了,为什么$b还是&#39;apple&#39;

其实是这样的,unset()这是将一个变量指针销毁了,并没有释放掉那块内存区域(变量容器),所以执行完操作之后,内存指向只是变成了这样:

&#39;apple&#39; <- $b

要牢记重点: unset()并没有释放变量所指向的那块内存(变量容器),而只是将变量指针销毁了。同时,将那块内存的 引用计数 (ref count) 减1,当引用计数为0时,也就是说当那块内存(变量容器)不被任何变量引用时,便会触发php的垃圾回收。

用代码来验证一下:

$a = &#39;apple&#39;;
$b = &$a;

$before = memory_get_usage();
unset($a);
$after = memory_get_usage();

var_dump($before - $after);  // 结果为int(0),没有释放
$a = &#39;apple&#39;;
$b = &$a;

$before = memory_get_usage();
unset($a, $b);
$after = memory_get_usage();

var_dump($before - $after);  // 结果为int(24),得到释放

直接回收

那要怎样做才能真正释放掉 &#39;apple&#39; 所占用的内存呢?

利用上述方法,我们可以在 unset($a) 之后再 unset($b) ,将内存区域的所有引用都销毁,引用计数减为0了,自然就被php回收了。

当然,还有更直接的方法:

$a = null;

直接赋值 null 会将将 $a 所指向的内存区域置空,并将引用计数归零,内存便被释放。


脚本执行结束

php是脚本语言,当脚本执行结束之后,脚本内使用的所有内存都会被释放。那么,我们手动去释放内存有意义吗?其实关于这个问题,早有解答,推荐大家看一下鸟哥 @laruence 2012年发表的一篇文章:请手动释放你的资源(Please release resources manually)

引用赋值

$a = &#39;apple&#39;;
$b = &$a;

上述代码中,我将一个字符串赋值给变量a,然后将a的引用赋值给了变量b。显然,这个时候的内存指向应该是这样的:

$a -> 'apple' <- $b

a和b指向了同一块内存区域(变量容器),我们通过 var_dump($a, $b) 得到 string(5) "apple" string(5) "apple" ,这是我们预期的结果。


引用计数 与 unset( )

假如我想将 'apple' 这个字符串从内存中释放掉。我是这么做的:

unset($a);

但是通过再次打印 $a $b 两变量的信息,我得到了这样的结果:Notice: Undefined variable: astring(5) "apple" 。奇怪,$a $b 同时指向一块内存区域,又明明将$a释放了,为什么$b还是'apple'

其实是这样的,unset()这是将一个变量指针销毁了,并没有释放掉那块内存区域(变量容器),所以执行完操作之后,内存指向只是变成了这样:

'apple' <- $b

要牢记重点: unset()并没有释放变量所指向的那块内存(变量容器),而只是将变量指针销毁了。同时,将那块内存的 引用计数 (ref count) 减1,当引用计数为0时,也就是说当那块内存(变量容器)不被任何变量引用时,便会触发php的垃圾回收。

用代码来验证一下:

$a = 'apple';
$b = &$a;

$before = memory_get_usage();
unset($a);
$after = memory_get_usage();

var_dump($before - $after);  // 结果为int(0),没有释放
$a = 'apple';
$b = &$a;

$before = memory_get_usage();
unset($a, $b);
$after = memory_get_usage();

var_dump($before - $after);  // 结果为int(24),得到释放

直接回收

那要怎样做才能真正释放掉 'apple' 所占用的内存呢?

利用上述方法,我们可以在 unset($a) 之后再 unset($b) ,将内存区域的所有引用都销毁,引用计数减为0了,自然就被php回收了。

当然,还有更直接的方法:

$a = null;

直接赋值 null 会将将 $a


참조 계산 및 unset()🎜🎜 문자열 'apple'을 메모리에서 해제하고 싶다고 가정해 보겠습니다. 🎜rrreee🎜 그러나 두 변수 $a $b의 정보를 다시 인쇄하여 다음과 같은 결과를 얻었습니다. 주의: 정의되지 않은 변수 : astring(5) "apple". 이상하게도 $a $b는 동시에 메모리 영역을 가리키며 $a를 명확하게 해제합니다. 왜 $b는 여전히 '사과'. 🎜🎜실제로는 unset()이 변수 포인터를 파괴하고 메모리 영역(변수 컨테이너)을 해제하지 않습니다. 따라서 작업이 완료된 후에는 메모리 포인터가 이렇게 됩니다. : 🎜rrreee🎜기억해야 할 핵심 사항: unset()은 변수가 가리키는 메모리(변수 컨테이너)를 해제하지 않고 변수 포인터만 파괴합니다. 동시에 해당 메모리 조각의 참조 카운트(ref count)는 1씩 감소합니다. 참조 카운트가 0일 때, 즉 해당 메모리 조각(변수 컨테이너)이 어떤 변수에서도 참조되지 않으면 PHP의 가비지 수집이 시작됩니다. 🎜🎜코드로 확인하세요: 🎜rrreeerrreee
🎜직접 재활용🎜🎜그럼 'apple'이 차지하는 메모리를 실제로 해제하려면 어떻게 해야 할까요? 🎜🎜위 방법을 사용하면 unset($a)를 한 다음 unset($b)하여 메모리 영역의 모든 참조를 삭제하고 참조 횟수를 0으로 줄일 수 있습니다. , 그것은 자연스럽게 PHP에 의해 재활용됩니다. 🎜🎜물론 더 직접적인 방법도 있습니다. 🎜rrreee🎜 null을 직접 할당하면 $a가 가리키는 메모리 영역이 비워지고 참조 횟수가 0으로 재설정됩니다. , 메모리가 해제됩니다. 🎜
🎜스크립트 실행 종료🎜🎜php는 스크립트 실행이 끝나면 스크립트에 사용된 모든 메모리가 해제되는 스크립트 언어입니다. 그렇다면 메모리를 수동으로 해제하는 것이 의미가 있습니까? 사실 이 질문은 오랫동안 답변되어 왔습니다. Brother Bird @laruence가 2012년에 게시한 기사: 리소스를 수동으로 릴리스하세요(리소스를 수동으로 릴리스하세요)🎜🎜참조 할당🎜rrreee🎜위 코드에서 읽어보시기 바랍니다. , I will 문자열이 변수 a에 할당된 다음 a의 참조가 변수 b에 할당됩니다. 당연히 이때 가리키는 메모리는 다음과 같아야 합니다. 🎜rrreee🎜a와 b가 동일한 메모리 영역(변수 컨테이너)을 가리키고, var_dump($a, $b)를 통해 를 얻습니다. > string(5) "apple" string(5) "apple" , 이는 예상된 결과입니다. 🎜
🎜참조 계산 및 unset()🎜🎜 문자열 'apple'을 메모리에서 해제하고 싶다고 가정해 보겠습니다. 제가 한 일은 다음과 같습니다. 🎜rrreee🎜 하지만 $a $b 두 변수의 정보를 다시 인쇄하여 다음과 같은 결과를 얻었습니다. 주의: 정의되지 않은 변수 : astring(5) "apple". 이상하게도 $a $b는 동시에 메모리 영역을 가리키며 $a를 명확하게 해제합니다. 왜 $b는 여전히 '사과'. 🎜🎜실제로는 unset()이 변수 포인터를 파괴하고 메모리 영역(변수 컨테이너)을 해제하지 않습니다. 따라서 작업이 완료된 후에는 메모리 포인터가 이렇게 됩니다. : 🎜rrreee🎜기억해야 할 핵심 사항: unset()은 변수가 가리키는 메모리(변수 컨테이너)를 해제하지 않고 변수 포인터만 파괴합니다. 동시에 해당 메모리 조각의 참조 카운트(ref count)는 1씩 감소합니다. 참조 카운트가 0일 때, 즉 해당 메모리 조각(변수 컨테이너)이 어떤 변수에서도 참조되지 않으면 PHP의 가비지 수집이 시작됩니다. 🎜🎜코드로 확인하세요: 🎜rrreeerrreee
🎜직접 재활용🎜🎜그럼 'apple'이 차지하는 메모리를 실제로 해제하려면 어떻게 해야 할까요? 🎜🎜위 방법을 사용하면 unset($a)를 한 다음 unset($b)하여 메모리 영역의 모든 참조를 삭제하고 참조 횟수를 0으로 줄일 수 있습니다. , 그것은 자연스럽게 PHP에 의해 재활용됩니다. 🎜🎜물론 더 직접적인 방법도 있습니다. 🎜rrreee🎜 null을 직접 할당하면 $a가 가리키는 메모리 영역이 비워지고 참조 횟수가 0으로 재설정됩니다. , 메모리가 해제됩니다. 🎜

위 내용은 PHP 스크립트의 메모리 관리 및 가비지 수집의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.