我们有一个简单的PHP函数,它的目的是调用一个C++自由函数std::string callLibrary(std::string)
并返回它的std::string
返回值。
它目前看起来是这样的:
PHP_FUNCTION(call_library)
{
char *arg = NULL;
size_t arg_len, len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE)
{
return;
}
// Call underlying library
std::string callResult = callLibrary(arg);
zend_string * result = zend_string_init(callResult.c_str(), callResult.size(), 0);
RETURN_STR(result);
}
我们找不到一本描述zend_string_init
或RETURN_STR()
行为的参考手册,我们所拥有的最接近的是:http://www.phpinternalsbook.com/php7/internal_types/strings/zend_strings.html
特别是,它对zend_string_init
的最后一个参数进行了说明
如果传递0,则要求引擎使用Zend内存管理器进行请求绑定的堆分配。此类分配将在当前请求结束时销毁。如果你不自己做,在调试版本上,引擎会对你大喊你刚刚造成的内存泄漏。如果您传递1,您将请求我们所说的“持久”分配,即引擎将使用传统的C malloc()调用,并且不会以任何方式跟踪内存分配。
看起来我们需要0
的值,但是RETURN_STR()
会释放分配的内存吗?(文本有点模棱两可,但看起来破坏应该是明确的)有没有一种更常用的方法从std::string
扩展函数返回这样的PHP值?
发布于 2018-06-11 05:30:59
为了回答您的问题,我将先简单介绍一下PHP内存分配,然后再讨论您的具体问题。
关于PHP内存分配
在编写PHP扩展时,您可以执行两种内存分配:
跟踪的内存分配
跟踪内存分配是一种优化,允许PHP引擎对原始内存分配有更多的控制。Zend内存管理器(ZendMM)充当标准内存分配库之上的包装器。此内存管理器允许PHP通过清理任何未在请求结束时显式释放的跟踪内存来避免内存泄漏。此外,这允许引擎设定内存限制(例如php.ini
设置memory_limit
)。由于这些原因,跟踪内存也称为按请求内存。
持久内存分配是由C库(例如malloc
和朋友)管理的标准内存分配。同样值得注意的是,在C++中,new
和delete
通常分别向下调用malloc
和free
。在PHP中,持久性内存分配在处理请求后仍然有效,它的存在可能是为了服务于多个请求。因此,使用这些类型的分配可能会导致内存泄漏。
在PHP中,有一些宏是为执行跟踪或持久内存分配而定义的。例如,emalloc
和efree
类似于malloc
和free
,用于跟踪(即按请求)内存管理。宏pemalloc
和pefree
用于跟踪或持久分配,它们有一个可切换的参数。例如,pemalloc(32,1)
分配32个持久字节块,而pemalloc(32,0)
等效于emalloc(32)
分配32个跟踪字节的块。
除了原始内存分配函数之外,PHP API还提供对由更高级别函数发起的内存分配的控制。例如,通过使用zend_string_init
创建PHP7 zend_string
结构,您可以通过第三个参数选择所需的内存分配类型。这在整个应用程序接口中遵循一个常见的习惯用法,0
表示跟踪分配,1
表示持久分配。
关于zend_string
**,** zend_string_init
和zend_string
**,的
我对PHP7并不像对PHP5那么熟悉,但是我已经继承了很多概念,我想我已经阅读了足够多的源代码来回答这个问题。当您使用RETURN_STR
将zend_string
分配给zval
时,zval
将负责释放zend_string
(在PHP5中,这只是一个char*
,但概念是相同的)。Zend引擎希望使用跟踪的内存管理器分配大多数对象。在PHP5中,分配给zval
的字符串必须是通过emalloc
分配的,因为当zval
被销毁时,代码总是在字符串缓冲区上调用efree
。在PHP7中,似乎有an exception,因为zend_string
结构可以记住使用了哪种分配类型。无论如何,最好始终使用跟踪的分配作为默认值,除非您有很好的理由这样做。因此,您当前的代码看起来不错,因为它将0
作为第三个参数传递给zend_string_init
。
在您的代码中不应该显式地销毁zend_string
,因为zval
将在以后的某个时间处理该问题。此外,该过程依赖于用户空间如何在返回的zval
上操作。这不是你必须担心的事情。
https://stackoverflow.com/questions/50465101
复制相似问题