PHP使用引用计数和写时复制来管理内存。
写时复制保证了变量间复制值不浪费内存,引用计数保证了不再需要时将内存释放给操作系统。
要能正确理解php内存管理之前,首先要了解符号表的概念。
一个变量有两个部分,他的名字(例如$name)和他的值(如 Fred)。
符号表是一个将变量名映射到内存中变量值所在地址的数组。
可以想象成符号表是这样一个数组 $signtable[变量名] = {对应值所在的地址} ;
当将一个变量的值复制到另一个变量时,PHP没有为复制值使用更多的内存。相反,它会更新符号表来说明两个变量
拥有相同的内存块,所以下面的代码实际上并没有创建一个新的数组:
$worker = array("Fred" , 35 , "Wilma") ;
$other = $worker ; //数组不被复制
如果后来修改了任意一个副本,PHP将分配所需的内存来进行复制 :
$worker[1] = 36 ; //值改变,数组被复制
通过延迟分配和复制,php在很多情形下节省了时间和内存,这就是写时复制。
符号表中的每一个值都有一个引用计数器,它的数值表示获取那片内存的方式的数目。
在给$worker 和 $other 初始化赋值后,数组指向了符号表,$worker 和 $other的引用计数器的值为2。换句话说,
那块内存有两种方式可以得到:通过$worker 和 $other。但当$worker[1]被改变时,php为$worker创建了一个新的数组,至此,$worker和$other的引用计数器只有1。
当一个变量离开作用域,如函数参数和局部变量到达函数末尾时, 它的值的引用计数器减1.当一个变量在其他内存空间被赋值时旧值的引用计数减1。当引用技术的值为0时,它的内存被释放。这就是引用计数。
引用计数是首选的管理内存的方式。保持变量作用域限制于函数中,通过值来传递,并让引用计数负责内存管理。如果你想主动获得更多的信息或控制权来释放一个变量的值,可以使用isset() 和 unset()函数。
如果要查看一个变量是否被设置甚至是空字符串,可以使用isset()
$s1 = isset($name);
$name = "Fred" ;
$s2 = isset($name);
使用unset()可删除一个变量的值:
$name = "Fred";
unset($name);