PHP内核学习笔记

1.#define ZEND_FN(name) zif_##name ##连接符
2.
#define ALLOC_ZVAL(z)                                   \
do {                                                \ 
   (z) = (zval*)emalloc(sizeof(zval_gc_info));     \
    GC_ZVAL_INIT(z);                                \
} while (0)
在php中经常使用do-while的宏定义,好处是,可以确保执行的正确性和只执行一次
如果不使用do-while 那么 #define TEST(a,b) a++;b++; 在if(test) TEST(a,b)中会产生语法错误


3.Zend引擎是PHP实现的核心,提供了语言实现上的基础设施


4.PHP实现内部,所有变量使用同一种数据结构(zval)来保存,不仅仅储存变量的值,也储存变量的类型


5.PHP中的三种类型
* 标量类型:boolean、integer、float(double)、string 
* 复合类型:array、object 
* 特殊类型:resource、NULL


6.zval中的字段,引用计数,是否为引用,值,类型
zval的存储结构

1 typedef struct _zval_struct zval;
2 ...
3 struct _zval_struct {
4 /* Variable information */
5 zvalue_value value;     /* 值 */
6 zend_uint refcount__gc; //引用计数 垃圾回收用
7 zend_uchar type;    /* 类型 */
8 zend_uchar is_ref__gc; //是否是引用
9 };
其中zvalue_value的结构
01 typedef union _zvalue_value {
02 long lval;                  /* long value */
03 double dval;                /* double value */
04 struct { //字符串
05      char *val;
06      int len;
07  } str;
08  HashTable *ht;              /* 数组 */
09  zend_object_value obj; //对象
10  } zvalue_value;
boolean integer float的值存储在lval中
string存储在struct中 存储了字符串的长度 因此strlen()函数可以在常数时间获得字符串长度


8.hash表使用非常广泛  哈希表通常提供查找(Search),插入(Insert),删除(Delete)等操作,这些操作在最坏的情况下和链表的性能一样为O(n)


9.PHP中HashTable的实现就是采用链地址法方式来解决冲突的,在最差的情况下,所有的键被映射到一个槽中,复杂度为O(n),良好的哈希函数可以解决


10. php中使用time33算法进行hash键值的计算,没有直接乘以33,而是用了 hash<<5+hash
time33算法也很简单,就是不断的乘33


11.PHP的hash表容量范围 2^3 到 2^31,会自动对幂进行取整
hash(key)=key&nTableMask
即简单将数据的原始key与HashTable的nTableMask进行按位与即可

12.PHP的哈希表碰撞攻击,利用方法将hash表的效率降为O(n),一般采用预防的方法是
1.限制Post参数的个数 (弊端,采用json格式无法预防)
2.升级php版本
根本解决办法,限制每个桶链表的最大长度,或者用红黑树取代链表(在普通情况下效率降低了)


13.常量的数据结构=变量的实际结果zval+常量标记+常量名+模块号 (模块号不是文件名,比如用户用define定义的常量都是PHP_USER_CONSTANT)


14.PHP内核变量作用域的实现:
PHP变量存储在一个HashTable实现的符号表里。当在PHP中调用一个函数或者类时,内核会创建一个新的符号表,这也是为什么在函数中无法使用函数外部定义的变量的原因。因为他们分属两个符号表,一个当前作用域,一个全局作用域


15. PHP内存管理主要工作就是维护三个列表:小块内存列表(free_buckets)、 大块内存列表(large_free_buckets)和剩余内存列表(rest_buckets) 这些列表都采用双向链表实现
从内存分配的过程中可以看出,内存块查找判断顺序依次是小块内存列表,大块内存列表,剩余内存列表




16.在释放一个变量的时候,会减少这个变量的refcount,当refcount为0时进行释放


17.PHP的垃圾回收机制在PHP5.3之前只有引用计数,为0释放,但是解决不了循环引用的问题
在PHP5.3以后,引入了垃圾收集机制,在zval字段后添加了__gc
如果变量的引用计数为1,即减一后引用计数为0,直接清除变量。如果当前变量如果被缓存,则需要清除缓存
如果变量的引用计数大于1,即减一后引用计数大于0,则将变量放入垃圾列表。如果变更存在引用,则去掉其引用。
垃圾回收以位来标记状态,GC_WHITE白色垃圾 GC_PURPLE紫色放入缓冲区
GC_GREY灰色表示进行了一场refcouont的减一操作
GC_BLACK默认颜色,正常
初始化的时候垃圾回收机制会直接调用malloc给整个缓存列表分配10000个gc_root_buffer内存空间
寻找垃圾的原则:如果一个zval的refcount减少之后大于0,那么此zval还不能被释放,此zval可能成为一个垃圾
当缓冲区被节点塞满的时候,GC才开始开始对缓冲区中的zval节点进行垃圾判断
垃圾回收算法主要的原理是,比较zval的引用计数与指向他的元素数量
如果指向他的元素等于引用计数,说明每一个元素都是引用的他自身,可以释放
如果不等于计数,那就不可以释放


主要是解决了简单计数法无法释放循环引用造成内存泄漏的问题


18.PHP中$i++会比++$i慢一些,在C++中 i++更快


19.用i+=1代替i=i+1。符合c/c++的习惯,效率还高


20.对global变量,应该用完就unset()掉


21.循环内部不要声明变量,尤其是大变量:对象


22.PHP变量赋值采用写时复制,即使不用引用,在如 $a=$b; 执行后,$a和$b指向的数据仍然相同
原理是zval中的引用计数


23.如果要进行操作的值已经是引用类型(如已经被&操作符操作过), 则直接重新分配内存,否则只是将value的地址赋与变量,同时将值的zval_value.refcount进行加1操作


24.不推荐使用 & ,让PHP自己决定什么时候该使用引用好了, 除非你知道自己在做什么(PHP内部已经有类似于引用的机制,对相同变量的复制采用COW)




















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值