background image

深入探讨 PHP 中的内存管理问题

 

 

一、 内存

在 PHP 中,填充一个字符串变量相当简单,这只需要一个语句""即可,并且该字符

串能够被自由地修改、拷贝和移动。而在 C 语言中,尽管你能够编写例如"char *str = 
"hello world ";"这样的一个简单的静态字符串;但是,却不能修改该字符串,因为它生
存于程序空间内。为了创建一个可操纵的字符串,你必须分配一个内存块,并且通过一个
函数(例如 strdup())来复制其内容。

以下为引用的内容:

  {

  char *str;

  str = strdup("hello world");

  if (!str) {

  fprintf(stderr  

, "Unable to allocate memory!");

  }

  }

  由于后面我们将分析的各种原因,传统型内存管理函数(例如
malloc(),free(),strdup(),realloc(),calloc(),等等)几乎都不能直接为 PHP 源代
码所使用。

  

 

二、 释放内存

  在几乎所有的平台上,内存管理都是通过一种请求和释放模式实现的。首先,一个应
用程序请求它下面的层(通常指"操作系统"):"我想使用一些内存空间"。如果存在可用的
空间,操作系统就会把它提供给该程序并且打上一个标记以便不会再把这部分内存分配
给其它程序。

  当应用程序使用完这部分内存,它应该被返回到 OS;这样以来,它就能够被继续分
配给其它程序。如果该程序不返回这部分内存,那么 OS 无法知道是否这块内存不再使用
并进而再分配给另一个进程。如果一个内存块没有释放,并且所有者应用程序丢失了它,
那么,我们就说此应用程序"存在漏洞",因为这部分内存无法再为其它程序可用。

  在一个典型的客户端应用程序中,较小的不太经常的内存泄漏有时能够为 OS 所"容
忍",因为在这个进程稍后结束时该泄漏内存会被隐式返回到 OS。这并没有什么,因为
OS 知道它把该内存分配给了哪个程序,并且它能够确信当该程序终止时不再需要该内存。

  而对于长时间运行的服务器守护程序,包括象 Apache 这样的 web 服务器和扩展
php 模块来说,进程往往被设计为相当长时间一直运行。因为 OS 不能清理内存使用,所
以,任何程序的泄漏-无论是多么小-都将导致重复操作并最终耗尽所有的系统资源。

  现在,我们不妨考虑用户空间内的 stristr()函数;为了使用大小写不敏感的搜索来查
找一个字符串,它实际上创建了两个串的各自的一个小型副本,然后执行一个更传统型
的大小写敏感的搜索来查找相对的偏移量。然而,在定位该字符串的偏移量之后,它不再
使用这些小写版本的字符串。如果它不释放这些副本,那么,每一个使用 stristr()的脚本
在每次调用它时都将泄漏一些内存。最后,web 服务器进程将拥有所有的系统内存,但