php - 在PHP扩展中,推荐的方法从and std::string返回值

标签 php c++ memory-management php-extension

我们有一个简单的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_initRETURN_STR()行为的引用手册,这是我们最近的事情:
http://www.phpinternalsbook.com/php7/internal_types/strings/zend_strings.html

特别是,它声明了zend_string_init的最后一个参数

If you pass 0, you ask the engine to use a request-bound heap allocation using the Zend Memory Manager. Such allocation will be destroyed at the end of the current request. If you don’t do it yourself, on a debug build, the engine will shout at you about a memory leak you just created. If you pass 1, you ask for what we called a “persistent” allocation, that is the engine will use a traditional C malloc() call and will not track the memory allocation in any way.



似乎我们需要0值,但是RETURN_STR()是否可以释放分配的内存? (文本有点模棱两可,但似乎破坏应该是明确的)
是否有更惯用的方法从PHP扩展函数返回此类std::string值?

最佳答案

为了回答您的问题,我将简单介绍一下PHP内存分配,然后再讨论您的特定问题。

关于PHP内存分配

编写PHP扩展时,可以执行两种内存分配:

  • 跟踪内存分配
  • 持久内存分配

  • 跟踪的内存分配是一种优化,它允许PHP引擎对原始内存分配进行更多控制。 Zend内存管理器(ZendMM)充当标准内存分配库之上的包装器。该内存管理器允许PHP通过清除所有在请求结束时未明确释放的跟踪内存来避免内存泄漏。此外,这允许引擎制定内存限制(例如php.ini设置 memory_limit )。由于这些原因,跟踪的内存也称为每个请求的内存。

    持久性内存分配是由C库管理的标准内存分配(例如malloc和friends)。还值得注意的是,在C++中,newdelete通常分别调用mallocfree。在PHP中,持久性内存分配在处理一个请求后仍然存在,并且可能存在以服务多个请求。因此,使用这种分配可能导致内存泄漏。

    在PHP API中,定义了一些宏以执行跟踪的或持久的内存分配。例如,emallocefreemallocfree的类似物,用于跟踪(即每个请求)的内存管理。宏pemallocpefree用于跟踪分配或持久分配,具有可切换的参数。例如,pemalloc(32,1)分配32个持久性字节的块,而pemalloc(32,0)等效于emalloc(32)分配32个跟踪字节的块。

    除了原始内存分配功能外,PHP API还提供了对由更高级别功能启动的内存分配的控制。例如,使用zend_string创建一个PHP7 zend_string_init结构可让您通过第三个参数选择所需的内存分配类型。这遵循整个API的通用习惯用法,0指示跟踪的分配,1指示持久性的分配。

    关于zend_stringzend_string_initRETURN_STR

    我对PHP7的了解不如对PHP5的熟悉,但是许多概念已经延续了下来,我认为我已经阅读了足够的源代码来回答这个问题。当您使用zend_stringzval分配给RETURN_STR时,zval负责释放zend_string(在PHP5中,这只是char*,但概念相同)。 Zend引擎期望使用跟踪的内存管理器分配大多数(如果不是全部)对象。在PHP5中,必须通过zval分配分配给emalloc的字符串,因为当efree被销毁时,该代码总是在字符串缓冲区上调用zval。在PHP7中似乎有an exception,因为zend_string结构可以记住使用了哪种分配类型。无论如何,除非有充分的理由,否则始终将跟踪的分配用作默认值是一个好习惯。因此,您当前的代码看起来不错,因为它将0作为第三个参数传递给zend_string_init
    zend_string的销毁不应在您的代码中明确显示,因为zval将在以后的某个时间进行处理。另外,该过程取决于用户空间如何对返回的zval进行操作。这不是您不必担心的事情。

    关于php - 在PHP扩展中,推荐的方法从and std::string返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50465101/

    相关文章:

    c++ - 算法分析大O和正常符号

    c++ 变体没有这样的文件或目录

    c++ - hashmap 的内存高效数据结构 (c++)

    PHP 数组使用 Laravel 合并到批量插入

    php - 我想在 WordPress 的 CSS 中添加背景图片

    c++ - DirectShow:网络摄像头预览和图像捕获

    objective-c - 卡住和恢复 Cocoa 任务或线程?

    ios - 通过分配保留 self 对象是个好主意吗

    php - 在我的 VPS 上将没有扩展名的文件作为 PHP 脚本处理

    phpmyadmin 403 php 在 CentOS 7 Apache 上从 7.4 -> 7.3 降级后被禁止