PHP 7如何从常规列表中删除资源?
作者:互联网
我正在将php扩展名升级到php 7,并且我想使用zend_register_resource删除已在常规列表中注册的资源,稍后再使用zend_list_close关闭该资源.关闭函数如下所示:
PHP_FUNCTION(myFunc_cleanAndExit)
{
zval* rsrc = NULL;
...
int res = zend_parse_parameters(ZEND_NUM_ARGS() , "r", &rsrc );
if (res == FAILURE)
{
//handle it
}
...
zend_fetch_resource(Z_RES_P(rsrc), ./other args/..)
...
zend_list_close(Z_RES_P(rsrc));
...
}
最初在PHP 5中,使用zend_hash_index_del(& EG(regular_list),Z_RESVAL_P(rsrc))删除了rsrc,因此,如果两次调用此函数,则zend_parse_parameter返回FAILURE,因为该资源已从常规列表中删除并且不存在.
在PHP7中,zend_list_close调用zend_resource_dtor(rsrc refcount为2(为什么在资源注册后为1递增?),然后清除rsrc占用的所有内存.但是,有趣的是,当我们这样两次调用它时:
myFunc_cleanAndExit($var-rsrc);
myFunc_cleanAndExit($var-rsrc);
第二次zend_parse_parameter不返回FAILURE(因为尚未从常规列表中删除资源),并且在解析后rsrc的refcount增加到3,类型为-1并且ptr为NULL(在第一个调用中的zend_resource_dtor).当我在PHP脚本中调用get_resources()时,我得到了带有其ID和类型UNKOWN的rsrc,在PHP5中rsrc变为NULL.这是我的问题:
1-什么时候从常规列表中删除资源? (如果我使用zend_hash_index_del从常规列表中手动将其删除,则会在zend_alloc中中断)
2-关闭一次后是否可以将资源激活为UNKOWN类型?不吃光记忆吗?如果不是,我应该怎么做才能将其设置为NULL?
3-当我注册资源并检查其引用计数时,它是1,但是当我调用关闭函数时,在zend_parse_parameter之后,引用计数增加了,为什么?
谢谢
示例PHP脚本:
<?php
$var_rsrc = myFunc_startUp();
var_dump($var_rsrc); // resource(2) of type 'MyFunc'
myFunc_cleanAndExit($var_rsrc);
var_dump($var_rsrc); // resource(2) of type 'UNKOWN' (originally this was NULL)
myFunc_cleanAndExit($var_rsrc);
var_dump($var_rsrc); // resource(2) of type 'UNKOWN'
解决方法:
简短的答案是资源在请求关闭时被删除,特别是在zend_hash_graceful_reverse_destroy中.您还应该检查zend_fetch_resource的返回值,因为它将为被破坏的资源返回NULL(并发出警告).
我认为您所描述的一切都是正常的,包括zend_parse_parameters成功地解析了先前被破坏的资源.下面的程序表现出完全相同的行为:
<?php
$r = popen('ls', 'r');
echo fgets($r);
pclose($r);
var_dump(get_resources());
pclose($r);
您的资源的引用计数为2,因为SEND_VAR操作码(即,将参数传递给函数)会将其ZVAL_COPY传递给arglist,这会增加引用计数. (稍后在zend_vm_stack_free_args中取消引用.)
关于内存使用情况,我不必担心资源耗尽内存.我们已经知道它不会泄漏,因为它会在RSHUTDOWN中被清理.即使您要手动从哈希中删除该项目,我也不认为可以保证立即将底层内存释放.
标签:php-internals,php-extension,php-7,php 来源: https://codeday.me/bug/20191118/2032133.html