Memory Usage
Posted: Sun Dec 19, 2010 10:50 am
I have a problem of memory usage causing a fatal error.
I called the following code in my home.php file.
The field "b" doesn't actually exist so in the database class it catches the error and then trys to log it using the log class.
The insert statement of the log class fails to execute, therefore a loop occurs as the database class trys to log this error, causing a build up of memory usage.
Any ideas on what is causing it?
Database Class:
Log Class:
Code: Select all
Fatal error: Allowed memory size of 68157440 bytes exhausted (tried to allocate 11851666 bytes) in /home/xxx/xxx/xxx/resources/classes/database.php on line 136
Code: Select all
$db->query("SELECT b FROM users");
The insert statement of the log class fails to execute, therefore a loop occurs as the database class trys to log this error, causing a build up of memory usage.
Any ideas on what is causing it?
Database Class:
Code: Select all
<?
/**
* News Muncher Database Class
*
* The Database class is meant to simplify the task of accessing
* information from the website's database.
*
* Written by: Ben Web Developer.com
* Last Updated: 25 October 2010
* Version: 0.1.0
*/
class Database {
/**
* The pdo database object
*
* @access private
* @var object
*/
private $dbh;
/**
* The mysqli prepared statement database object
*
* @access private
* @var object
*/
private $stmt;
/**
* Whether to show SQL/DB errors
*
* @since 0.1.0
* @var bool
*/
var $show_errors = false;
/**
* The start time of the query
*
* @since 0.1.0
* @var string
*/
var $query_start_time;
/**
* Time taken to execute the query
*
* @since 0.1.0
* @var string
*/
var $query_time;
/**
* Total time taken to execute all queries
*
* @since 0.1.0
* @var string
*/
var $total_query_time;
/**
* Amount of queries made
*
* @since 0.1.0
* @var int
*/
var $num_queries = 0;
/**
* Amount of queries that contained errors
*
* @since 0.1.0
* @var int
*/
var $num_error_queries = 0;
/**
* Results of the last query
*
* @since 0.1.0
* @var array
*/
var $last_result = array();
/**
* Class constructor
*
* @since 0.1.0
* @var bool
*/
public function __construct() {
try {
// Connect to database
$this->dbh = new PDO("mysql:host=".SERVER.";dbname=".NAME.";", USER, PASS, array( PDO::ATTR_PERSISTENT => true ));
// Set the PDO error mode to exception
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e) {
// Show errors if enabled
if($this->show_errors) {
echo $e->getMessage();
echo $e->getLine();
}
return false;
}
}
/**
* Query the database
*
* @access public
* @since 0.1.0
* @var bool
*/
public function query($sql, $params = array()) {
global $log, $page_handler;
// Try and execute the query
try {
// Start query execution time
$this->query_start_time = microtime(true);
// Prepare the sql statement
$this->stmt = $this->dbh->prepare($sql);
// Bind the parameters
if( count($params) > 0 )
$this->stmt = $this->bind_params($this->stmt, $params);
// Execute the statment
$this->stmt->execute();
// Debug
echo size_format(memory_get_usage(), 4).' - '.$sql.' '.$this->stmt->columnCount().'<br />';
// Fetch Results
/**
* Using the column count of the statement we can determine if the sql statement was a update, insert, delete or select etc.
* Therefore we can see if we need to return a result set or not.
*/
if( $this->stmt->columnCount() > 0 )
$this->fetch_all();
else
$this->last_result = array();
// Calculate query time and add it onto the total query time.
$this->query_time = microtime(true) - $this->query_start_time;
$this->total_query_time = $this->total_query_time + $this->query_time;
// Increase the number of queries
$this->num_queries++;
// Return true upon success
return true;
}
catch (PDOException $e) {
/**
* Increase the number of error queries and stop the query time.
*/
$this->num_error_queries++;
$this->query_start_time = 0;
/**
* Log and show the error if enabled
* The exception handler will return a trace of the error, we can use this to determine where the error occured.
* We need to use the template file and not the class file to determine where the error is, hence why we return
* the 2nd row in our array.
*/
$log->add('database', $page_handler->url, $e->getTrace());
if( $this->show_errors ) {
echo '<pre><h4>Database Error</h4>';
echo '<strong>SQL Statement:</strong> '.$e->getMessage().'<br />';
echo '<br /><strong>Error Trace</strong><br /><br />';
foreach ($e->getTrace() as $key => $value) {
echo '<strong>File:</strong> '.$value['file'].'<br />';
echo '<strong>Line Number:</strong> '.$value['line'].'<br /><br />';
}
echo '</pre>';
}
// Return false upon failure
return false;
}
}
/**
* Dynamically bind parameters
*
* @access private
* @since 0.1.0
* @var object
*/
private function bind_params($stmt, $params) {
try {
foreach($params as $key => &$value)
{
$stmt->bindParam($key, $value);
}
return $stmt;
}
catch (PDOException $e) {
// Show errors if enabled
if($this->show_errors)
echo $e->getMessage();
echo $e->getLine();
//Log errors
return false;
}
}
/**
* Get insert id from last query
*
* @access public
* @since 0.1.0
* @var int
*/
public function getLastInsertId() {
return $this->dbh->lastInsertId( );
}
/**
* Fetch all of the records returned from the query
* and set the last_result variable.
*
* @since 0.1.0
* @var array
*/
private function fetch_all() {
$this->last_result = $this->stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Get the number of rows returned from the query
* Applies to select queries.
*
* @since 0.1.0
* @var string
*/
public function get_num_rows() {
return count($this->last_result);
}
/**
* Get number of affected rows from last query
* Applies to update, insert and delete queries
*
* @access public
* @since 0.1.0
* @var int
*/
public function get_affected_rows() {
return $this->stmt->rowCount();
}
}
Code: Select all
<?
/**
* News Muncher Log Class
*
* The Log class is meant to simplify the task of logging
* any errors the website generates.
*
* Written by: Ben Web Developer.com
* Last Updated: 19 December 2010
* Version: 0.1.0
*/
class Log {
public function add($type, $url, $info) {
global $db, $user_management;
$db->query('INSERT INTO log (type, url, information, timestamp, username, ip, read) VALUES (:type, :url, :information, :timestamp, :username, :ip, :read)', array(':type' => $type, ':url' => $url, ':information' => serialize($info), ':timestamp' => time(), ':username' => $user_management->username, ':ip' => $_SERVER['REMOTE_ADDR'], ':read' => '0'));
return true;
}
public function show() {
global $db;
$db->query('SELECT type, url, information, timestamp, read FROM log');
return $db->last_result;
}
}