代码之家  ›  专栏  ›  技术社区  ›  Will Shaver

如何避免PHP对象嵌套/创建限制?

  •  1
  • Will Shaver  · 技术社区  · 15 年前

    我在PHP中有一个手工创建的ORM,它似乎碰到了对象限制,导致PHP崩溃。下面是一个将导致崩溃的简单脚本:

    <?
    class Bob
    {
        protected $parent;  
        public function Bob($parent)
        {
            $this->parent = $parent;
        }
    
        public function __toString()
        {
            if($this->parent)
                return (string) "x " . $this->parent;
            return "top";
        }
    }
    
    
    $bobs = array();
    for($i = 1; $i < 40000; $i++)
    {
        $bobs[] = new Bob($bobs[$i -1]);
    }    
    ?>
    

    即使从命令行运行它也会导致问题。有些盒子能装40000多件物品。我在Linux/Apache上尝试过(失败),但我的应用程序运行在IIS/FastCGI上。在fastcgi上,这会导致著名的“fastcgi进程意外退出”错误。

    显然,20K对象有点高,但如果对象具有数据和嵌套复杂性,则崩溃的对象要少得多。

    快速CGI不是问题-我试过从命令行运行它。我试过将内存设置为非常高的6000MB和非常低的24MB。如果我把它设置得足够低,我会得到“分配的内存大小XXX字节用尽”的错误。

    我认为这与被称为某种筑巢预防的功能的数量有关。我不认为我的ORM筑巢这么复杂,但也许是。我有一些非常清楚的例子,如果我再加载一个对象,它就会死掉,但是如果它工作的话,它会在3秒内加载。

    1 回复  |  直到 7 年前
        1
  •  4
  •   Frank Farmer    15 年前

    有趣的是,在我的环境中,当需要解构对象时,似乎会出现segfault——在循环运行正常之后放置的代码。只有当PHP开始关闭时,才会出现segfault。

    你可以 file a bug 但是您可能会发现,PHP的维护人员不会竭尽全力支持这类事情。我看过至少一个关于内存泄漏的bug报告,其中官方的回应基本上是“wontfix:内存在页面呈现后释放,所以这并不重要”--实际上意味着在快速呈现网页和终止的简单情况之外使用并不真正受支持。

    经过5年的全职PHP开发,我得出了一个简单的规则:如果它崩溃了,就不要这样做。PHP有其局限性,如果你不突破这些局限性,你会发现自己最成功。

    这意味着要避免 create_function() 在php<=5.2中(它像疯了一样泄露内存)。你可以试着用 创建_函数() 把PHP当作一种函数语言来使用。不是的,如果你这样使用它,你会发现它失败得很惨。

    所以如果PHP在40000层深的嵌套对象上阻塞…不要在40000层深处筑巢。另一种可能的选择是使用数组而不是对象——但这听起来仍然相当糟糕。