我在运行我的一个脚本时不断收到此错误;
PHP 致命错误:允许的内存大小 已耗尽的 1073741824 字节数(已尝试 分配 71 字节)在 ... lib/symfony-1.4.11/lib/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection/Statement.php 在第 246 行,...
以下是脚本的精简版本触发错误;
public function executeImportFile(sfWebRequest $request)
{
ini_set('memory_limit', '1024M');
set_time_limit ( 0 );
//more codes here...
$files = scandir($workspace.'/'.$directory);
foreach ($files as $file) {
$path = $workspace.'/'.$directory.'/'.$file;
if ($file != "." && $file != "..") {
$this->importfile($path);
}
}
}
protected function importfile($path){
$connection =
sfContext::getInstance()->getDatabaseManager()->getDatabase('doctrine')->getDoctrineConnection();
$connection->beginTransaction();
try {
//more codes here...
while ($data = $reader->read()) //reads each line of a csv file
{
// send the line to another private function to be processed
// and then write to database
$this->writewave($data);
}
$connection->commit();
} catch (Exception $e) {
$connection->rollback();
}
}
该脚本所做的基本上是读取文件夹(每个包含数万行),处理它,并使用 Doctrine 的事务将其写入数据库。
虽然我认为我不需要设置内存限制和时间限制在这两个函数中,脚本退出,因为 Doctrine 用完了所有分配了 1GB 内存。
它通常会在处理 10 个文件并分配更多文件后停止内存将允许它处理更多的文件,并且仍然崩溃。
我在这里缺少什么导致内存不处理完每个文件后释放?
莫哈末·沙基尔·扎卡里亚http://www.mohdshakir.net
尽可能释放任何对象,包括查询/连接对象,尤其是当它们位于循环内时。
http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/improving-performance.html#free-objects
处理大型数据集时会使用大量内存 - 以这种方式导入大型/多个文件是不可能的。
即使您在单独的函数调用中导入每个文件,doctrine 也有一个内部对象缓存,因此它们不会被释放。
最好的选择是稍微修改任务,使其接受文件名作为参数。如果已通过,则仅处理该文件(希望它不会变得太大)。如果没有传递文件名,它会像现在一样遍历所有文件,并通过 exec
调用自己,所以这是一个不同的过程,内存真的被释放了。
我在你的脚本中看到的最大问题是你经常调用sfcontext。恕我直言,sfcontext 不是单例,这意味着您每个循环都会创建一个新实例。您不能将连接传递到方法中吗?
public function executeImportFile(sfWebRequest $request)
{
ini_set('memory_limit', '1024M');
set_time_limit ( 0 );
$connection = sfContext::getInstance()->getDatabaseManager()->getDatabase('doctrine')->getDoctrineConnection();
//more codes here...
$files = scandir($workspace.'/'.$directory);
foreach ($files as $file) {
$path = $workspace.'/'.$directory.'/'.$file;
if ($file != "." && $file != "..") {
$this->importfile($path, $connection);
}
}
}
protected function importfile($path, $connection){
$connection->beginTransaction();
try {
while ($data = $reader->read()) //reads each line of a csv file
{
$this->writewave($data);
}
$connection->commit();
} catch (Exception $e) {
$connection->rollback();
}
}