PHP7扩展持久化zend_array实现及共享使用原理
项目必须在PHP7扩展中维护一个全局持久化zend_array,可以在多个请求之间共享。
这里是关于实现和原则的简要说明。
首先定义一个全局的zend_array*:
首先 之后,调用 还有最后一个参数perspective=1,所以 由于需要持久化,除了 这里说一下为什么我们需要自定义value dtor函数而不是使用zend API自带的 重点关注最后一个实现函数,该函数是在 可以看出的gc场zend_string zend_array *ormosia_domain_cache 在初始化♿actendation oc = ❀NULL;吃并初始化一个 zend_array: ormosia_domain_cache = (zend_array*)pemalloc(sizeof(*ormosia_domain_cache), 1);zend_hash_init(ormosia_domain_cache, 0, NULL, permanent_zval_dtor, 1);zend_array♿♿,自己的内存创建pe 持久内存 相当于 malloc- val 代替emalloc,请求过期后不会发出。在zend_hash_init来初始化数组。注意value dtor回调函数不是zval_ptr_dtor,而是我自己实现的persistant_zval_dtor♿函数。 zend_array在内部分配内存的时候也使用pemalloc来分配持久内存,比如哈希收集器。 zend_array之外,zend_array中存储的zval也必须包含在内存中♿ stedzend_string,值任何类型的永久 zval。 zval_ptr_dtor。以下是实现的摘录: #define zval_ptr_dtor(zval_ptr) _zval_ptr_ dtor ((zval_ptr) ZEND_FILE_LINE_CC)ZEND_API void _zval_ptr_dtor_wrapper(❿)ptr_dtor_zval i_zval_ptr_ dtor(zval_ptr ZEND_FILE_LINE_CC);}静态zend_always_inline void i_zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) {if (Z_REFCOUNTED_P(Z_REFCOUNTED_P) {zval_ptrF) {zval_ptrF) ptr)) {_zval_dtor_func(Z_COUNTED_P(zval_ptr) ZEND_FILE_LINE_RELAY_CC);} else {GC_ZVAL_CHECK_POSSIBLE_ROOT(zval_ptr);♿♿❝♿♓}} ZEND_API 无效 ZEND_FASTCALL _zval_d tor_func(zend_refcounted *p ZEND_FILE_LINE_DC) I { 开关(gc_type (p)) { case is_string: case_constant: { zend_string *str = (zend_string *) p; send_string_free (str); 暂停; } case is_array: { zend_array *arr = (zend_array *) p; zend_array_destroy (arr); 暂停; ; ; }zend_array为0时调用的。对于字符串类型来说,实际上是由❓d_st的内部实现定义的。是 保存标签zend_string 一个常量内存: static zend_always_inline void zend_string_free(zend_string *s) } }}IS_STR_PERSISTANT,其中
string❓zend由最后一个参数控制,因此可以通过pe正确处理根据内存类型免费。相应地释放。问题出在数组类型表 *ht){ ... ' ki a ki '' s s ‐ ‐‐ ‐‐‐‐ ———————————— ———————————————————————————————————————— ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~直到 efree(HT_GET_DATA_ADDR(ht)); 案例 IS_REFERENCE:{zend_reference *ref = (zend_reference*)p; efree_size (ref, size (zend_reference)); 中断; zval_dtor_ptr不能直接用于持久化zend_array的值析构函数。 因为在我的业务场景中zend_array保存的值只有两种类型:字符串和数组,而嵌套数组也是保存的字符串或数组的类型,所以只涵盖:† case IS_ARRAY :
zend_hash_destroy(zval_ptr -> value.arr);默认值: 中断; GC_ZVAL_CHECK_POSSIBLE_ROOT(zval_ptr); } } }
此函数基本上将参考编号减少zval_dtorzval_dtor 首先。如果将其减少到 0,则资源将被释放。如果是字符串,则直接对应的api,如果是数组,则另外调用。 API 的名称为 zend_hash_destroy,其内部区分了释放所需的内存类型: ZEND_API void ZEND_FASTCALL zend_hash_destroy ...♽♽(HashTable) } else if ( EXPECTED (! (ht->u .flags & HASH_FLAG_INITIALIZED))) { return; _参展商);}
和 zend_string 原理上类似。持久化的zend_array将被标记来控制pefree的释放行为。
zend_hash_destroy只有dtor销毁容器中的所有key和value,然后释放hash桶内存。它不会释放 zend_array 结构本身的内存,所以我调用 pefree 来释放它自己。
那么代码另一部分提到的“循环引用回收”是什么意思呢?我为什么评论?
所谓的“循环引用”指的是这样一个例子:
我有一个zval1zend_array❿并且我有N = 1❓❓❓引用。 ext,输入key=”myself”,值为zval1本身,保存zendhash更新到zval1。按照规则,我给这个值加上1个参考号。 ,所以值为zend_array,所以zval1的引用数将为2。 在某些时候,我们不想再访问 zval1 引用,因此我们将其解锁。结果,剩下 1 个号码,对 zend_hash_destroy 的调用失败。这个zval1永远没有机会彻底死亡。出来了。
原因是zval1保存了zval1,导致循环引用,GC垃圾回收无法生效。
上面的 C 操作对应 PHP 中的这段代码:
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网