PHP是一种弱类型的脚本语言,弱类型不表示PHP变量没有类型的区别,PHP变量有8种原始类型:
四种标量类型:php
两种复合类型:程序员
两种特殊类型:算法
在引擎内部,变量都是用一个结构体来表示的。这个结构体能够在{PHPSRC}/Zend/zend.h中找到:编程
struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount__gc; //表明一个计数器,表示有多少个变量名指向这个zval容器 zend_uchar type; /* active type */ zend_uchar is_ref__gc; //此字段是一个布尔值,用来标识变量是不是一个引用,经过这个字段,PHP引擎能够区分通常变量和引用变量 };
父进程fork子进程以后,子进程的地址空间仍是简单的指向父进程的地址空间,只有当子进程须要写地址空间中的内容的时候,才会单独分离一份给子进程,这样就算子进程立刻调用exec函数也没有关系,由于根本就不须要从父进程的地址空间中拷贝内容,这样就节省了内存同时又提升了速度。这个逻辑能够叙述为:对一个通常变量a(isref=0)进行通常的赋值操做,若是a所指向的zval的计数refcount大于1,那么须要为a从新分配一个新的zval,而且把以前的zval的计数refcount减小1。数组
几个基本准则:函数
新的GC算法目的就是防止循环引用的变量引发内存泄露问题。在PHP中GC算法,当节点缓冲区满了以后,垃圾分析算法就会启动,而且会释放掉发现的垃圾,从而回收内存。ui
如今,若是咱们试一下,将数组的引用赋值给数组中的一个元素,有意思的事情发生了:spa
<?php $a = array("one"); $a[] = &$a; ?>
这样$a数组就有两个元素,一个索引为0,值为字符one,另外一个索引为1,为$a自身的引用,内部存储以下:3d
a: (refcount=2, is_ref=1)=array ( 0 => (refcount=1, is_ref=0)='one', 1 => (refcount=2, is_ref=1)=... )
“...”表示1指向a自身,是一个环形引用(循环引用):code
这个时候咱们对$a进行unset,那么$a会从符号表中删除,同时$a指向的zval的refcount减小1。
<?php $a = array('one'); $a[] = &$a; unset($a); ?>
那么问题产生了,$a已经再也不符号表中了,用户没法再访问此变量,可是$a以前指向的zval的refcount变为1而不是0,所以不能被回收,这样产生了内存泄露:
这样zval就成为一个垃圾了,新的GC要作的工做就是清理这种垃圾。
在PHP编程中程序员不须要手动处理内存资源分配与释放,意味着PHP自己实现了垃圾回收处理机制。
这个算法叫作“引用计数”,其思想很是直观和简洁:为每一个内存对象分配一个计数器,当一个内存对象创建时计数器初始化为1(所以此时老是有一个变量引用此对象),之后每有一个新变量引用此内存对象,则计数器加1,而每当减小一个引用此内存对象的变量则计数器减1,当垃圾回收机制运做时,将全部计数器为0的内存对象销毁并回收其占用的内存。而php中内存对象就是zval,而计数器就是refcount__gc。