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也必须包含在内存中♿ sted
zend_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前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。