php释放内存-【php7拓展系列】显存与字符串相关

2023-08-27 0 8,973 百度已收录

上面写:

swoole的出现让PHP不仅在Web领域进入了其他领域。 PHP7的性能提升再次拓宽了PHP的应用范围,比如游戏领域。 不过,PHP7为了提高性能,改变了大量Zenda API。 看到新版本的Zenda API,相信你的第一反应是变化太大了!为什么不兼容之前的呢,还是那句话是为了性能提升,所以基本上所有的php扩展都需要分支来支持php的新版本。 对于扩展开发者来说,需要同时维护两套代码。 使用扩展的人为每个php版本编译不同的so文件很麻烦。 本文将尝试从另一个角度解决这个问题——通过引入一套兼容层函数,尽可能少的改变扩展代码,一套代码支持所有php.ini。 不过这个方案已经在 swoole 和 php-cp(pdo 和 redis 代理)项目中得到成功应用,下面会分几个部分讲一下具体实现以及为什么在 php7 改成这样

内存字符串相关

1.MAKE_STD_ZVAL

php7最大的改变就是内存部分。 首先,新设计的zval、zend_string、hashtable(ng中也称为zend_array)等数据结构小而紧凑,可以充分利用CPU缓存。 其次,使用大量的堆栈空间。 而不是在堆中申请显存,扩展级别的反应是去掉MAKE_STD_ZVAL和ALLOC_INIT_ZVAL等显存申请的宏定义,因为phpng的zendapi在申请显存后不需要将地址传递给zendapi堆(其实如果业务确实需要你可以自动emalloc显存),在swoole和php-cp中怎么做呢? 首先,将扩展中的所有MAKE_STD_ZVAL替换为SW_MAKE_STD_ZVAL 其次,我们看一下SW_MAKE_STD_ZVAL的定义:

#if PHP_MAJOR_VERSION < 7
#define SW_MAKE_STD_ZVAL(p)               MAKE_STD_ZVAL(p)
#else#define SW_MAKE_STD_ZVAL(p)      zval _stack_zval_##p; p = &(_stack_zval_##p) 
//宏展开后就是在栈上定义的zval#endif

可见php释放内存,在phpng中,SW_MAKE_STD_ZVAL是在栈上定义一个zval,并将地址参数交给p。 在以前的php版本中php释放内存,是直接调用MAKE_STD_ZVAL。 注意:该方法可以适应大部分使用MAKE_STD_ZVAL的地方,但有时Hou(例如:将MAKE_STD_ZVAL得到的指针作为函数内部函数的返回值返回)是不能接受的,需要自动emalloc,如一开始就说了“通过引入一组兼容层函数来尽量减少对扩展代码的修改”。

2.zval_ptr_dtor

在之前的php版本中,zval_ptr_dtor将参数传递为针的针,而在phpng中,则是zval的针。 首先将扩展中的所有zval_ptr_dtor替换为sw_zval_ptr_dtor(下面不再赘述)。 兼容的宏代码如下:

#if PHP_MAJOR_VERSION < 7
#define sw_zval_ptr_dtor                       zval_ptr_dtor
#else#define sw_zval_ptr_dtor(p)         zval_ptr_dtor(*p) 
//用*操作把指针的指针变成指针(好绕口)#endif

有人可能会问,据说malloc显存是通过栈模拟的,那么这里释放显存会不会导致分段错误呢?

if (Z_REFCOUNTED_P(zval_ptr)) {        
   if (!Z_DELREF_P(zval_ptr)) {
       _zval_dtor_func_for_ptr(Z_COUNTED_P(zval_ptr) ZEND_FILE_LINE_RELAY_CC); } else {
       GC_ZVAL_CHECK_POSSIBLE_ROOT(zval_ptr); } }

如上,因为在phpng中释放显存之前,会判断如果不是引用变量类型,就会跳过,不做任何事情。

3.zval_add_ref

php释放内存-【php7拓展系列】显存与字符串相关

添加引用计数的方法:

#if PHP_MAJOR_VERSION < 7
#define sw_zval_add_ref                     zval_add_ref
#else#define sw_zval_add_ref(p)       Z_TRY_ADDREF_P(*p)
//phpng会先判断类型然后再加引用#endif

4. SW_ZVAL_STRING、SW_ZVAL_STRINGL、RETURN_STRINGL、RETVAL_STRINGL、RETURN_STRING

在以前的php版本中,这组函数的最后一个参数是是否复制字符串,如下:

 Z_STRVAL_P(__z) = (duplicate?estrndup(__s, Z_STRLEN_P(__z)):(char*)__s);
//duplicate就是上述一组函数的最后一个参数

不过phpng中仍然返回zend_string,并且不需要重复参数,所以兼容的宏如下:

#if PHP_MAJOR_VERSION < 7
#define SW_ZVAL_STRINGL                          ZVAL_STRINGL
#define SW_ZVAL_STRING                            ZVAL_STRING
#define SW_RETURN_STRINGL                    RETURN_STRINGL
#define SW_RETURN_STRING                      RETURN_STRING
#define SW_RETVAL_STRINGL                      RETVAL_STRINGL
#else
#define SW_ZVAL_STRINGL(z, s, l, dup) ZVAL_STRINGL(z, s, l) #define SW_ZVAL_STRING(z,s,dup) ZVAL_STRING(z,s) #define SW_RETURN_STRINGL(s, l, dup) RETURN_STRINGL(s, l) #define SW_RETURN_STRING(val, dup) RETURN_STRING(val) #define SW_RETVAL_STRINGL(s, l, dup) RETVAL_STRINGL(s, l); #endif

可以看出,dup参数在phpng中被简单地忽略了。 需要注意的是,如果你原来的代码中最后一个参数是0,但是第一个参数应用在堆上,那么efree(s)的第一个参数是必需的。 释放视频内存。

--------------大分割线----------------

PHPFamily(phpfamily)是由一群靠谱的人打造的,愿意给PHPer带来一些值得细细品味的精神食粮!

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 php php释放内存-【php7拓展系列】显存与字符串相关 https://www.wkzy.net/game/166218.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务