PHP内核原理(二)内存管理

本文深入探讨了PHP内核中zval的内存管理,包括值和引用的概念,引用计数和写时复制策略,以及如何在扩展中应用。详细解释了zval的创建、初始化、引用计数的增减、zval销毁的条件,并介绍了拷贝zval的不同方法,以及zval分离的场景和用途。
摘要由CSDN通过智能技术生成

转载请注明出处http://blog.csdn.net/fanhengguang_php

PHP内核原理 Zvals内存管理

zval结构有两个功能:第一,用于存储一个变量的值以及变量类型。第二,有效的管理内存中的zval变量的值,本章将会介绍这个功能。

接下来我们看一下引用计数和copy-on-write 这两个概念,以及在扩展中如何应用。

值和引用

在php中所有的变量都是值传递,除非你显示的指明引用传递。即任何时刻你传递一个变量给个函数或者给另外一个变量赋值,你得到的两个变量都会拥有一份独立的值的拷贝。看以下例子

<?php

$a = 1;
$b = $a;
$a++;

// Only $a was incremented, $b stays as is:
var_dump($a, $b); // int(2), int(1)

function inc($n) {
   
    $n++;
}

$c = 1;
inc($c);

// The $c value outside the function and the $n inside the function are distinct
var_dump($c); // int(1)

虽然上面例子有些简单,但需要意识到这是php种一个基本的规则, 特别的这个规则页适用于对象。

<?php

$obj = (object) ['value' => 1];

function fnByVal($val) {
    
    $val = 100;
}

function fnByRef(&$ref) {
    
    $ref = 100;
}

// The by-value function does not modify $obj, the by-reference function does:

fnByVal($obj);
var_dump($obj); // stdClass(value => 1)
fnByRef($obj);
var_dump($obj); // int(100)

人们经常说自从php5对象对象是自动的按引用传递的, 但是通过以上例子看出这是错的:按值传递的函数不能修改传递给他的变量,而按引用传递的函数可以。

看一下例子:

<?php
class myclass {
    
    public $prop;
}
function myfun($obj) {
    
    $obj->prop = 'world';
}
$obj = new myclass();
$obj->prop = 'hello';

var_dump($obj);
myfun($obj);
var_dump($obj);

打印出:

object(myclass)#1 (1) {
    
  ["prop"]=>
  string(5) "hello"
}
object(myclass)#1 (1) {
    
  ["prop"]=>
  string(5) "world"
}

对象确实表现出引用传递的行为:虽然你不能将其赋值为一个完全不同的值, 但是你可以在函数中修改对象的成员。这是由于对象的值仅仅是一个用来查找实际内容的ID, 引用传递可以阻止你将其ID改为一个不同的对象或者不同的类型,但是并不能阻止你修改对象的实际的值。

以上也适用于resource类型。因为它也是同样仅仅存储了用于查找实际值的ID,所以同样的按引用传递可以阻止你修改其resource ID或者不同的类型,但是并不能阻止你resource的内容(如修改文件的指针位置)。

引用计数和写时复制

稍加思考你会得到这样的结论:php一定是做了可怕的大量拷贝。每次给函数传递变量,其值都会被拷贝一次,对于整形int或者double类型这可能没啥问题,但是想像一下给函数传递一个拥有百万元素的数组,每次调用都拷贝百万的元素将是多么低效。

为了避免拷贝,php使用了写时复制的方法:一个zval可以被多个变量、函数等共享,只要他们对变量是只读的不会修改她。如果一个变量想要做修改,在修改之前需要将zval拷贝一份。

如果一个zval可以被共享,那么php需要一个方法判断何时这个zval不被使用了,不再使用的zval将会被释放掉。PHP通过简单的跟踪一个zval被引用次数来解决这个问题, 注意这里引用指的是一个zval被变量、函数等使用,而不是变量引用(如&方式引用变量)。引用个数存储在zval结构的refcount__gc成员变量中。

为了理解引用计数原理,考虑下面的例子:

<?php

$a = 1;    // $a =           zval_1(value=1, refcount=1)
$b = $a;   // $a = $b =      zval_1(value=1, refcount=2)
$c = $b;   // $a = $b = $c = zval_1(value=1, refcount=3)

$a++;      // $b = $c = zval_1(value=1, refcount=2)
           // 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值