Doctrine查询内存使用情况

时间:2009-09-11 19:09:30

标签: php doctrine memory-management

Doctrine似乎占用超过4MB的RAM来执行一个简单的查询:

print memory_get_peak_usage()." <br>\n";
$q = Doctrine_Query::create()
    ->from('Directories d')
    ->where('d.DIRECTORY_ID = ?', 5);

$dir = $q->fetchOne();
print $dir['name']." ".$dir['description']."<br>\n";

print memory_get_peak_usage()." <br>\n";

/***************  OUTPUT:  **************************

6393616
testname testdescription
10999648

/***************************************************/

这是在一个测试数据库中,其中包含非常少的数据 - 我查询的项目不包含除此处显示的数据之外的任何数据。

我的系统设置方式是否有问题,或者是Doctrine的标准内存使用情况?

7 个答案:

答案 0 :(得分:6)

从我所看到的,你的代码似乎没有错......


作为测试,我已经设置了一个快速示例,其中包含一个非常简单的表(仅限四个字段)

以下是相关代码:

var_dump(number_format(memory_get_peak_usage()));

$test = Doctrine::getTable('Test')->find(1);

var_dump(number_format(memory_get_peak_usage()));

这样做时,我有这种输出:

string '1,316,088' (length=9)
string '2,148,760' (length=9)

考虑到表格非常简单,而且我只提取了一行,对我来说似乎“太多”了 - 但这与你得到的结果非常一致,并且与我在其他项目中看到的一致: - (< / p>


如果您只需要显示数据,而不是使用它(即更新/删除/ ...),解决方案可能是不提取复杂对象,而只是一个简单的数组:

$test = Doctrine::getTable('Test')->find(1, Doctrine::HYDRATE_ARRAY);

但是,在这种情况下,它并没有太大的区别,实际上:-(:

string '1,316,424' (length=9)
string '2,107,128' (length=9)

只有40 KB的差异 - 好吧,有更大的物体/更多的线条,它可能仍然是一个好主意......


在Doctrine手册中,有一个名为Improving Performance的页面;也许它可以帮助你,特别是对于这些部分:


哦,顺便说一下:我在PHP 5.3.0上做过这个测试;也许这会对使用的内存量产生影响......

答案 1 :(得分:5)

我同意romanb的回答 - 在使用大型库/框架时,使用OpCode缓存是必须的。

与OpCode缓存相关的示例

我最近采用了Zend Framework的Doctrine用法并且对内存使用感到好奇 - 所以和OP一样,我创建了一个使用类似OPs测试标准的方法,并将其作为一个整体测试运行,看看ZF + Doctrine的峰值是什么内存使用情况。

我得到了以下结果:

没有APC的结果:

10.25 megabytes
RV David
16.5 megabytes

APC的结果:

3 megabytes
RV David
4.25 megabytes

操作码缓存会产生非常显着的差异。

答案 2 :(得分:4)

嗯,这个内存使用来自哪里?正如Pascal MARTIN所指出的那样,阵列水合作用并没有太大的区别,这在逻辑上是因为我们只是在谈论一些记录。

内存消耗来自通过自动加载按需加载的所有类。

如果您没有设置APC,那么是的,您的系统设置方式有问题。甚至不开始测量性能,并期望任何大型PHP库没有APC等操作码缓存的良好结果。除了第一个负载(APC需要首先缓存字节码)之外,它不仅可以加速执行,还可以减少所有页面加载的内存使用量至少50%。

4MB的简单示例真的闻起来像没有APC,否则它真的会有点高。

答案 3 :(得分:4)

在Doctrine Query上使用fetchOne()时要小心。此函数调用不会在SQL

上追加“限制1”

如果您只需要从DB获取一条记录,请确保:

$q->limit(1)->fetchOne() 

大表上的内存使用率大幅下降。

您可以看到fetchOne()将首先从数据库中提取为集合,然后返回第一个元素。

public function fetchOne($params = array(), $hydrationMode = null)
{
    $collection = $this->execute($params, $hydrationMode);

    if (is_scalar($collection)) {
        return $collection;
    }

    if (count($collection) === 0) {
        return false;
    }

    if ($collection instanceof Doctrine_Collection) {
        return $collection->getFirst();
    } else if (is_array($collection)) {
        return array_shift($collection);
    }

    return false;
}

答案 4 :(得分:2)

Doctrine在Doctrine_Record,Doctrine_Collection和Doctrine_Query上提供了一个free()函数,它消除了对这些对象的循环引用,将它们释放出来进行垃圾回收。 More info..

使内存使用量少一点您可以尝试使用以下代码:

  • $ record-&gt; free(true) - 将进行深度释放,对所有关系调用free()
  • $ collection-&gt; free() - 这将释放所有集合引用
  • Doctrine_Manager :: connection() - &gt; clean()/ clear() - 清理连接(并删除身份映射条目)
  • $查询 - &GT; free()的

答案 5 :(得分:1)

我猜大多数内存用于加载Doctrine的类,而不是用于与查询本身相关联的对象。

  • 您使用的是哪个版本的Doctrine?
  • 您使用的是自动加载器吗?

在Doctrine 1.1中,默认的自动加载行为称为“激进”,即使您在任何特定请求中仅使用一个或两个,它也会加载所有模型类。将该行为设置为“保守”将减少内存使用量。

答案 6 :(得分:0)

我刚刚使用symfony 1.4执行了“daemonized”脚本,并设置以下内容停止了内存占用:

sfConfig::set('sf_debug', false);