Jump to content

Memory Error Inconsistencies


ShadowMage

Recommended Posts

I have a script that is currently on a Windows system. It runs perfectly. However, when I tried to port it over to a Linux machine, it throws an error at me. This is the error I get:Fatal error: Allowed memory size of 16777216 bytes exhausted (tried to allocate 42 bytes) in /var/www/phplib/ODBC.php on line 101Now I can get it to work by inserting ini_set("memory_limit","48M"); at the top of the script. Then it works as it did on the windows machine. The thing I don't get is that the php.ini file on both machines is set to 16M so why is it throwing an error on the Linux box and not on windows?Any advice is much appreciated. Thank you.

Link to comment
Share on other sites

The basic answer is because everything on Linux is different. The only piece of information I see is from the error message, where it's using ODBC. So I'll use that as an example. On Windows you've got several different ODBC and ADO libraries. They're a pretty important part of Windows, a lot of things use them, so you can expect that they've been worked on quite a bit and have quite a bit of optimizations and things like that. The ODBC libraries on Linux might not be as well-maintained and might not have as much work put into them, so they may be more inefficient than the Windows libraries are. There could be any number of system libraries your code is using that may not be as efficient as their Windows counterparts.

Link to comment
Share on other sites

The ODBC.php in the error message refers to a file that was written by one of my predecessors at work. The same version of the file is on both machines. The file connects to the databases on our database server. So that can't be the issue, can it?

Link to comment
Share on other sites

The ODBC.php in the error message refers to a file that was written by one of my predecessors at work. The same version of the file is on both machines. The file connects to the databases on our database server. So that can't be the issue, can it?
It's possible... virtually anything is possible. It's also possible that it's not this file that has a memory leak, but rather, that the memory is completely exhausted at that point, after being heavily used by something else.Either way, PHP is internally using more memory for something on Linux than on Windows. The ODBC functions are the best candidates.
Link to comment
Share on other sites

So that can't be the issue, can it?
It's not the PHP code that is the issue, it's the system libraries. On Windows when PHP uses ODBC it goes through the Windows ODBC system libraries, provided by Microsoft. On Linux it probably uses libodbc or whatever else is available. It's those system libraries that have the differences, not the PHP code you're writing.Of course, if I saw all the PHP code there might be some obvious things that stood out as not being platform-independent.
Link to comment
Share on other sites

This is the ODBC.php file:

<?phpclass mysqlConnection {	var $conn_handle; //Connection handle		// class constructor	function mysqlConnection($database) {		// set the appropriate database information		$mysqlServer = "server";		$mysqlPass = "aPassword";		switch ( $database ) {			//set $mysqlUser as appropriate		default:			echo "MySQL database $database not found.  No connection established.";			return false;		}				$handle = mysql_connect($mysqlServer, $mysqlUser, $mysqlPass) or			die("<B>Error!</B> Couldn't Connect To Database. Error Code:  ".mysql_error());					mysql_select_db($database, $handle) or die('Could not select database');				$this->conn_handle = $handle;		return true;	}		function close() {		// close the database connection		mysql_close($this->conn_handle);	}	function execute($query) {		/**		For SELECT, SHOW, DESCRIBE or EXPLAIN statements, this function returns a			resource on success, or FALSE on error.		For other type of SQL statements, UPDATE, DELETE, DROP, etc, this function			returns TRUE on success or FALSE on error.		**/ 		return mysql_query($query, $this->conn_handle);	}		function fetch_row_num($res) {		/** returns a zero-based array of the row data **/		return mysql_fetch_array($res, MYSQL_NUM);	}		function fetch_row($res) {		/** returns a zero-based array of the row data **/		return mysql_fetch_array($res, MYSQL_ASSOC);	}	function get_recordset($query) {		$newRS = new odbcRecordset;		$arr = array();				$res = mysql_query($query, $this->conn_handle) 			or die("<B>Error!</B> Couldn't Run Query:<br><br>" . $query . "<br><br>Error Code:  ".mysql_error());				// iterate through resultset		$rownum = 0;		while($row = mysql_fetch_array($res, MYSQL_ASSOC)) {			$arr[$rownum] = $row;			$rownum++;		}				// done getting data - free the result		mysql_free_result($res);				// populate the recordset and return it		$newRS->SetData($arr, $rownum, $query);		return $newRS;	}	function get_array($query, $key_qty = 0) {		$arr = array();		$arrNames = array();		$arrVals = array();				$res = mysql_query($query, $this->conn_handle) 			or die("<b>Error!</b> Couldn't Run Query:<br /><br />".$query."<br /><br />Error Message:  ".mysql_error());				// iterate through resultset		$rownum = 0;		//Throws error on this line:		while($row = mysql_fetch_array($res, MYSQL_ASSOC)) {			if ($rownum == 0) {				foreach ($row as $key => $value) {					$arrNames[] = $key;				}			}						unset($arrVals);			foreach ($row as $value) {				$arrVals[] = $value;			}						switch ($key_qty) {				case 1:					$arr[$arrVals[0]] = array();					$arrTemp = &$arr[$arrVals[0]];					break;				case 2:					$arr[$arrVals[0]][$arrVals[1]] = array();					$arrTemp = &$arr[$arrVals[0]][$arrVals[1]];					break;				case 3:					$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]] = array();					$arrTemp = &$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]];					break;				case 4:					$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]] = array();					$arrTemp = &$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]];					break;				case 5:					$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]][$arrVals[4]] = array();					$arrTemp = &$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]][$arrVals[4]];					break;				case 6:					$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]][$arrVals[4]][$arrVals[5]] = array();					$arrTemp = &$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]][$arrVals[4]][$arrVals[5]];					break;				default:					$arr[] = array();					$arrTemp = &$arr[(count($arr) - 1)];					break;			}						for ($i = $key_qty; $i < count($arrVals); $i++) {				$arrTemp[$arrNames[$i]] = $arrVals[$i];			}						++$rownum;		}				// done getting data - free the result		mysql_free_result($res);				// return the array		return $arr;	}}class odbcConnection {	var $conn_handle; //Connection handle		// class constructor	function odbcConnection($dsn, $user, $pass) {		$handle = odbc_connect($dsn, $user, $pass, SQL_CUR_USE_ODBC) or			die("<B>Error!</B> Couldn't Connect To Database. Error Code:  ".odbc_error());				$this->conn_handle = $handle;		return true;	}		function close() {		// close the database connection		odbc_close($this->conn_handle);	}		function execute($query) {		/**		For SELECT, SHOW, DESCRIBE or EXPLAIN statements, this function returns a			resource on success, or FALSE on error.		For other type of SQL statements, UPDATE, DELETE, DROP, etc, this function			returns TRUE on success or FALSE on error.		**/ 		return odbc_exec($this->conn_handle, $query);	}		function fetch_row_old($res) {		/** fetches a row as an array **/		return odbc_fetch_array($res);	}	function fetch_row_num($res) {		/** returns a zero-based array of the row data **/		$arr = array();		odbc_fetch_into($res, $arr);		return $arr;	}		function fetch_row($res) {		return odbc_fetch_array($res);	}		function get_recordset($query) {		$newRS = new odbcRecordset;		$arr = array();				$res = odbc_exec($this->conn_handle, $query) 			or die("<B>Error!</B> Couldn't Run Query:<br><br>" . $query . "<br><br>Error Code:  ".mysql_error());				// iterate through resultset		$rownum = 0;		while($row = odbc_fetch_array($res)) {			$arr[$rownum] = $row;			$rownum++;		}				// done getting data - free the result		odbc_free_result($res);				// populate the recordset and return it		$newRS->SetData($arr, $rownum, $query);		return $newRS;	}	function get_array($query, $key_qty = 0) {		$arr = array();		$arrNames = array();		$arrVals = array();				$res = odbc_exec($this->conn_handle, $query) 			or die("<b>Error!</b> Couldn't Run Query:<br /><br />".$query."<br /><br />Error Message:  ".odbc_errormsg());				// iterate through resultset		$rownum = 0;		while($row = odbc_fetch_array($res)) {						if ($rownum == 0) {				foreach ($row as $key => $value) {					$arrNames[] = $key;				}			}						unset($arrVals);			foreach ($row as $value) {				$arrVals[] = $value;			}						switch ($key_qty) {				case 1:					$arr[$arrVals[0]] = array();					$arrTemp = &$arr[$arrVals[0]];					break;				case 2:					$arr[$arrVals[0]][$arrVals[1]] = array();					$arrTemp = &$arr[$arrVals[0]][$arrVals[1]];					break;				case 3:					$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]] = array();					$arrTemp = &$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]];					break;				case 4:					$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]] = array();					$arrTemp = &$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]];					break;				case 5:					$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]][$arrVals[4]] = array();					$arrTemp = &$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]][$arrVals[4]];					break;				case 6:					$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]][$arrVals[4]][$arrVals[5]] = array();					$arrTemp = &$arr[$arrVals[0]][$arrVals[1]][$arrVals[2]][$arrVals[3]][$arrVals[4]][$arrVals[5]];					break;				default:					$arr[] = array();					$arrTemp = &$arr[(count($arr) - 1)];					break;			}						for ($i = $key_qty; $i < count($arrVals); $i++) {				$arrTemp[$arrNames[$i]] = $arrVals[$i];			}						++$rownum;		}				// done getting data - free the result		odbc_free_result($res);				// return the array		return $arr;	}}class odbcProgressConn extends odbcConnection {	var $conn_handle; // Connection handle		// class constructor	function odbcProgressConn($database) {		$user = 'user';		$pass = 'aPassword';		$schema = "SET SCHEMA 'schema'";		switch ( $database ) {		//choose the database		default:			echo "Progress database $database not found.  No connection established.";			return false;		}				$handle = odbc_connect($database, $user, $pass, SQL_CUR_USE_ODBC) or			die("<B>Error!</B> Couldn't Connect To Database. Error Code:  ".odbc_error());		// set the database schema if specified		odbc_exec($handle, $schema);				$this->conn_handle = $handle;		return true;	}}class odbcSurfControlConn extends odbcConnection {	var $conn_handle; // Connection handle		// class constructor	function odbcSurfControlConn($database) {				$user = 'user';		$pass = 'aPassword';				$handle = odbc_connect($database, $user, $pass) or			die("<B>Error!</B> Couldn't Connect To Database. Error Code:  ".odbc_error());				$this->conn_handle = $handle;		return true;	}}class odbcRecordset {	var $recordcount;	var $currentrow;	var $eof;		var $recorddata;	var $query;		function __get($field_name) {		return $this->data($field_name);	}	function odbcRecordset() {		$this->recordcount = 0;		$this->recorddata = 0;	}		function GetColumnNames() {		return array_keys($this->recorddata[0]);	}		function SetData($newdata, $num_records, $query) {		$this->recorddata = $newdata;		$this->recordcount = $num_records;		$this->query = $query;		$this->currentrow = 0;		$this->set_eof();	}		function copyRef($arrayToCopy) {		$this->recorddata = &$arrayToCopy->recorddata;		$this->recordcount = $arrayToCopy->recordcount;		$this->query = $arrayToCopy->query;		$this->currentrow = 0;		$this->set_eof();	}		function set_eof() {		$this->eof = $this->currentrow >= $this->recordcount;	}		function movenext()  { if ($this->currentrow < $this->recordcount) { $this->currentrow++; $this->set_eof(); } }	function moveprev()  { if ($this->currentrow > 0) { $this->currentrow--; $this->set_eof(); } }	function movefirst() { $this->currentrow = 0; $this->set_eof(); }	function movelast()  { $this->currentrow = $this->recordcount - 1;  $this->set_eof(); }		function data($field_name) {		if (isset($this->recorddata[$this->currentrow][$field_name])) {			$thisVal = $this->recorddata[$this->currentrow][$field_name];		} else if ($this->eof) {			die("<B>Error!</B> eof of recordset was reached");		} else {			// a null value returned from the database will leave the field unset			// return an empty string if this occurs			$thisVal = "";		}				return $thisVal;	}}?>

Obviously I've edited a few things for security purposes, but the gist of it should be there. This is the line that is throwing the error:

while($row = mysql_fetch_array($res, MYSQL_ASSOC)) {

Link to comment
Share on other sites

It looks like it's saving all of the database results in an array. So, the memory required to store that information is going to increase proportionally with the amount of data in the database. It might just be the case that the database on the Windows server has less data than the other server. If you need all of the data in an array and have a lot of data to get, the only solution is to increase the memory available to the script. I've got some reports asking for up to 512MB of memory, not the most elegant way to go about it but I don't want the script to fail if the user decides to print everything out.

Link to comment
Share on other sites

The script is pulling from the exact same database so it's not a case of data inconsistencies. It must be the differences in the ODBC libraries as you had pointed out earlier, justsomeguy.Thank you for your patience and your advice. I'll probably have to look at optimizing the code a bit.Thanks again to both of you for your help.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...