php、mysql,我的内存泄漏

标签 php mysql memory-leaks

我没想到这个脚本(扔掉)会泄露,而且我还没弄清楚罪魁祸首是什么。你能发现什么吗?尽管这是一次性代码,但我担心将来会重复此操作。我从来没有必要在 PHP 中管理内存,但是随着数据库中行数的增加,它耗尽了我的 php 实例(已经将内存增加到 1Gb)。

california 表比其他表特别大(当前有 220 万行,当我删除重复行时会减少)。我在第 31 行收到内存错误 ($row = mysql_fetch_assoc($res))

Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocat e 24 bytes) in C:\Documents and Settings\R\My Documents\My Webpages\cdiac\cdiac_ dup.php on line 31

PHP 5.3.0,mysql 5.1.36。 wamp 安装的一部分。

这是完整的代码。这个脚本的目的是删除重复的条目(数据被获取到分段表中,这在当时要快得多,但现在我必须合并这些表。)

是什么原因造成的?我忽略了什么?或者我只需要观察内存大小并在内存变大时手动调用垃圾收集?

<?php

define('DBSERVER', 'localhost');
define('DBNAME', '---');
define('DBUSERNAME', '---');
define('DBPASSWORD', '---');

$dblink = mysql_connect(DBSERVER, DBUSERNAME, DBPASSWORD);
mysql_select_db(DBNAME, $dblink);


$state = "AL";
//if (isset($_GET['state'])) $state=mysql_real_escape_string($_GET['state']); 
if (isset($argv[1]) ) $state = $argv[1];

echo "Scanning $state\n\n";


// interate through listing of a state to check for duplicate entries (same station_id, year, month, day)
$DBTABLE = "cdiac_data_". $state;
$query = "select * from $DBTABLE ";
$query .= " order by station_id, year, month, day ";

$res = mysql_query($query) or die ("could not run query '$query': " . mysql_errno() . " " . mysql_error());

$last = "";
$prev_row;
$i = 1;
$counter = 0;
echo ".\n";
while ($row = mysql_fetch_assoc($res)) {  
  $current = $row["station_id"] . "_" . $row["year"] . "_" . sprintf("%02d",$row["month"]) . "_" . sprintf("%02d",$row["day"]);
  echo str_repeat(chr(8), 80) . "$i  $current ";
  if ($last == $current) {
    //echo implode(', ', $row) . "\n";

    // merge $row and $prev_row
    // data_id  station_id, state_abbrev, year, month,  day,  TMIN, TMIN_flags, TMAX, TMAX_flags, PRCP, PRCP_flags, SNOW, SNOW_flags, SNWD, SNWD_flags

    printf("%-13s %8s %8s\n", "data_id:", $prev_row["data_id"], $row["data_id"]);
    if ($prev_row["data_id"] == $row["data_id"]) echo " + ";

    $set = "";
    if (!$prev_row["TMIN"] && $row["TMIN"])  $set .= "TMIN = " . $row["TMIN"] . ", ";
    if (!$prev_row["TMIN_flags"] && $row["TMIN_flags"])   $set .= "TMIN_flags = '" . $row["TMIN_flags"] . "', ";
    if (!$prev_row["TMAX"] && $row["TMAX"])   $set .= "TMAX = " . $row["TMAX"] . ", ";
    if (!$prev_row["TMAX_flags"] && $row["TMAX_flags"])   $set .= "TMAX_flags = '" . $row["TMAX_flags"] . "', ";
    if (!$prev_row["PRCP"] && $row["PRCP"])   $set .= "PRCP = " . $row["PRCP"] . ", ";
    if (!$prev_row["PRCP_flags"] && $row["PRCP_flags"])   $set .= "PRCP_flags = '" . $row["PRCP_flags"] . "', ";
    if (!$prev_row["SNOW"] && $row["SNOW"])   $set .= "SNOW = " . $row["SNOW"] . ", ";
    if (!$prev_row["SNOW_flags"] && $row["SNOW_flags"])   $set .= "SNOW_flags = '" . $row["SNOW_flags"] . "', ";
    if (!$prev_row["SNWD"] && $row["SNWD"])   $set .= "SNWD = " . $row["SNWD"] . ", ";
    if (!$prev_row["SNWD_flags"] && $row["SNWD_flags"])   $set .= "SNWD_flags = '" . $row["SNWD_flags"] . "', ";

    $delete = "";
    $update = "";
    if ($set = substr_replace( $set, "", -2 )) $update = "UPDATE $DBTABLE SET $set WHERE data_id=".$prev_row["data_id"]." and year=".$row["year"]." and month=".$row["month"]." and day=".$row["day"].";\n";
    if ($row["data_id"] != $prev_row["data_id"]) $delete = "delete from $DBTABLE where data_id=".$row["data_id"]." and year=".$row["year"]." and month=".$row["month"]." and day=".$row["day"].";\n\n";

    if ($update) {
      $r = mysql_query($update) or die ("could not run query '$update' \n".mysql_error());
    }
    if ($delete) {
      $r = mysql_query($delete) or die ("could not run query '$delete' \n".mysql_error());
    }    

    //if ($counter++ > 5) exit(0);
  }
  else {
    $last = $current;
    unset($prev_row);
    //copy $row to $prev_row
    foreach ($row as $key => $val) $prev_row[$key] = $val;
  }

  $i++;
}

    echo "\n\nDONE\n"; 
?>

最佳答案

我会尝试两件事:

1) 不要使用 mysql_query 在循环内运行 UPDATE 和 DELETE 查询,而是将它们保存在文本文件中,以便稍后执行。例如:file_put_contents('queries.sql', $update, FILE_APPEND );

2)不要在 while ($row = mysql_fetch_assoc($res)) 循环中执行所有操作,而是首先获取所有 SELECT 查询结果,然后关闭数据库连接,释放所有数据库资源,包括查询结果。只有在此之后,才执行循环过程。

如果在将数据库结果存储在一个数组中时内存不足,您可以尝试将结果保存在临时文件中(每行一条记录/FILE_APPEND),然后在循环中使用该文件(读取一行每条记录,使用 fgets 函数)。

关于php、mysql,我的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7218093/

相关文章:

php - Android JSONPARSER致命异常: AsyncTask

python - 使用 PyQtGraph 时如何清除 `while` 循环中的绘图?

ios - 当内存消耗攀升但 Leaks 未检测到泄漏时,如何处理 iOS 中的泄漏?

php - Symfony 2 根据选定值动态更改表单

javascript - 通过ajax调用发送php变量

php - 带有选择选项的mysql未知错误

PHP/MYSQL 根据另一个条件检索名称

mysql - 将 Mysql 查询转换为 Mongodb find()

mysql - 如何在 SQL 中获取两种不同类型的用户

swift - 保留类和结构之间的循环