php常量数据写内存 php的数据是怎么样存在内存中的( 三 )


你可能会注意到 即使是pefree()函数也要求使用永久性标志 这是因为在调用pefree()时 它实际上并不知道是否ptr是一种永久性分 配 针对一个非永久性分配调用free()能够导致双倍的空间释放 而针对一种永久性分配调用efree()有可能会导致一个段错误 因为内存管理器会试 图查找并不存在的管理信息 因此 你的代码需要记住它分配的数据结构是否是永久性的 除了分配器函数核心部分外 还存在其它一些非常方便的ZendMM特定的函数 例如void *estrndup(void *ptr int len);该函数能够分配len+ 个字节的内存并且从ptr处复制len个字节到最新分配的块 这个estrndup()函数的行为可以大致描述如下
复制代码代码如下: void *estrndup(void *ptr int len) { char *dst = emalloc(len + ); memcpy(dst ptr len); dst[len] = ; return dst; }
在 此 被隐式放置在缓冲区最后的NULL字节可以确保任何使用estrndup()实现字符串复制操作的函数都不需要担心会把结果缓冲区传递给一个例如 printf()这样的希望以为NULL为结束符的函数 当使用estrndup()来复制非字符串数据时 最后一个字节实质上都浪费了 但其中的利明显 大于弊void *safe_emalloc(size_t size size_t count size_t addtl); void *safe_pemalloc(size_t size size_t count size_t addtl char persistent);这 些函数分配的内存空间最终大小是((size*count)+addtl) 你可以会问 "为什么还要提供额外函数呢?为什么不使用一个 emalloc/pemalloc呢?"原因很简单 为了安全 尽管有时候可能性相当小 但是 正是这一"可能性相当小"的结果导致宿主平台的内存溢出 这可能会导致分配负数个数的字节空间 或更有甚者 会导致分配一个小于调用程序要求大小的字节空间 而safe_emalloc()能够避免这种类型的陷 井 通过检查整数溢出并且在发生这样的溢出时显式地预以结束注意 并不是所有的内存分配例程都有一个相应的p*对等实现 例如 不存在pestrndup() 并且在PHP 版本前也不存在safe_pemalloc()
五 引用计数慎重的内存分配与释放对于PHP(它是一种多请求进程)的长期性能有极其重大的影响 但是 这还仅是问题的一半 为了使一个每秒处理上千次点击的服务器高效地运行 每一次请求都需要使用尽可能少的内存并且要尽可能减少不必要的数据复制操作 请考虑下列PHP代码片断
复制代码代码如下: <?php $a = Hello World ; $b = $a; unset($a); ?>
在第一次调用之后 只有一个变量被创建 并且一个 字节的内存块指派给它以便存储字符串"Hello World" 还包括一个结尾处的NULL字符 现在 让我们来观察后面的两行 $b被置为与变量$a相同的值 然后变量$a被释放 如 果PHP因每次变量赋值都要复制变量内容的话 那么 对于上例中要复制的字符串还需要复制额外的 个字节 并且在数据复制期间还要进行另外的处理器加 载 这一行为乍看起来有点荒谬 因为当第三行代码出现时 原始变量被释放 从而使得整个数据复制显得完全不必要 其实 我们不妨再远一层考虑 让我们设想 当一个 MB大小的文件的内容被装载到两个变量中时会发生什么 这将会占用 MB的空间 此时 已经足够了 引擎会把那么多的时间和内存浪费在这 样一种无用的努力上吗? 你应该知道 PHP的设计者早已深谙此理 记住 在引擎中 变量名和它们的值实际上是两个不同的概念 值本身是一个无名的zval*存储体(在本例中 是一个字符串值) 它被通过zend_hash_add()赋给变量$a 如果两个变量名都指向同一个值 会发生什么呢?
复制代码代码如下: { zval *helloval; MAKE_STD_ZVAL(helloval); ZVAL_STRING(helloval "Hello World" ); zend_hash_add(EG(active_symbol_table) "a" sizeof("a") helloval sizeof(zval*) NULL); zend_hash_add(EG(active_symbol_table) "b" sizeof("b") helloval sizeof(zval*) NULL); }

推荐阅读