PHP源码解析——字符串

字符串结构

struct _zend_string{
    zend_refcount_h gc;        //8字节,gc引用计数
    zend_ulong      h;         //8字节,字符串的哈希值(仅在作为数组key时用到)
    size_t          len;       //8字节,记录字符串的长度,空间换时间,保证二进制安全
    char            var[1];    //1字节,柔性数组,字符串的值存储位置
}
  • gc字段:存放引用计数,使得其和数组、对象一样,可以被多个zval引用
  • h字段:存储字符串的哈希值,只有当字符串需要被作为数组的key时才会被初始化,同一个字符串被多次当做key使用时,不会重复计算其对应的哈希值
  • len字段:记录字符串的长度,类型是size_t(long unsigned int),有两方面作用,一方面是用空间换时间,避免重复计算字符串长度,另一方面是为了保证二进制安全,和C语言不同,C语言字符串默认以\0结尾,所以不支持存储二进制数据,而PHP的字符串长度是通过len记录的,不会因为二进制数据中的\0而提前结束,所以可以存储二进制数据。
  • val字段:存储字符串值,采用柔性数组,所谓柔性数组,就是结构体最后一个变量,占用末尾连续的一块内存。分配字符串内存时,一次申请内存大小为结构体大小+字符串长度+1(C字符串结尾追加\0),所以字符串的值与结构体中其他成员存储在同一块连续的空间中,在分配释放内存中可以直接当成整体处理,相比PHP5节省了一次读取字符串值时的内存读写。

智能字符串

typedef struct{
    zend_string    *s;    //字符串值存储在zend_string.val中
    size_t          a;    //存储申请的内存空间总大小
}smart_str

       字符串申请内存时,会先申请一块较大的连续内存,申请的内存长度存储到smart_str中,把已使用的长度写到smart_str.s.len字段中,当字符串需要追加新字符串时,直接检查剩余内存块长度够不够,够了则直接追加,不够则重新申请一块更大的内存。通过空间换时间,避免了每次追加都需要重新申请内存。

字符串销毁

       IN_STR_INTERNED标签标记的字符串,不会走PHP的内存池函数,这类字符串包含funciton、class、static、object等保留字符串,以及用户手动定义的字面字符串、变量名使用的字符串。在解析AST生成oparray时,会将这些字符串写入CG(interned_strings)数组中,从而避免重复浪费内存,且销毁方便(只需要遍历销毁interned_strings数组)。

  1. cli模式下的PHP进程:每次执行完都会调用php_module_shutdown,在这个阶段会调用zend_interned_strings_dtor函数销毁整个interned_strings数组。
  2. 未开启opcode下的PHP-FPM进程:fpm进程只有执行够max_request次数后才会执行php_module_shutdown,但是在php_request_shutdown阶段会调用zend_interned_restore_int方法销毁内部字符串。
  3. 开启opcache下的PHP-FPM进程:在php_request_shutown阶段不会销毁,常驻内存,只有在进程结束时才会被销毁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AirGo.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值