【发布时间】:2011-11-05 07:04:42
【问题描述】:
我没想到这个脚本(丢弃)会泄漏,我还没有弄清楚罪魁祸首是什么。你能发现什么吗?尽管这是一次性代码,但我担心我将来会重复此操作。我从来不需要在 PHP 中管理内存,但是由于数据库中的行数,它正在炸毁我的 php 实例(已经将内存增加到 1Gb)。
california 表比其他表特别大(当前为 220 万行,因为我删除了重复行而减少了)。第 31 行出现内存错误 ($row = mysql_fetch_assoc($res))
致命错误:允许的内存大小为 1073741824 字节已用尽(已尝试 在 C:\Documents and Settings\R\My Documents\My 中分配 24 个字节) 第31行的网页\cdiac\cdiac_dup.php
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";
?>
【问题讨论】:
-
虽然在我删除内容时它会变小,但我的加利福尼亚表有 2,200,000 多行。我用完了大约 170 万行的内存(设置为 1Gb)。
-
您应该使用现代 mysql 扩展之一
MySQLi或PDO_MYSQL。 -
@kingcruch,我相信你是对的。您是否有任何偏好或明确的理由来使用其中一种?
-
@fbas:mysqli 级别较低,PDO 级别较高。 mysqli 允许更多地访问 MySQL 特定的功能。 PDO 有更好的接口,支持其他 DB。见问题"mysqli or PDO - what are the pros and cons?"。
标签: php mysql memory-leaks