Fatal error: Allowed memory size of ... bytes exhausted

Odpowiedz Nowy wątek
2018-12-23 21:51
0

Dzień dobry.

Mam następujący problem. Piszę skrypt w PHP. Napisałem moduł instalacyjny, tworzący bazę danych i użytkownika i wypełniający bazę niezbędnymi danymi. Skrypt działał, aż do momentu, gdy dodałem funkcję wypisującą zawartość tabeli MySQL do tabeli HTML. Zaczął pojawiać się komunikat:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate [262K] bytes)

Niestety, nie wiem, czemu, ale od kiedy pojawia się ten komunikat w związku z wypisywaniem danych na ekran, pojawia się on również podczas instalacji (a wcześniej instalacja przechodziła bezproblemowo). Czy jest możliwe że serwer cache'uje wyniki zapytań i przepełnił mu się licznik? To bez sensu.

Próbowałem zwiększać memory_limit z 128M na 256M, ale nadal d***. Proszę o pomoc, co to może być i dlaczego skrypt, który wcześniej działał, nagle przestał?

Używam XAMPP na Windows z bazą MySQL

Dzięki Michał

Pozostało 580 znaków

2018-12-23 22:22
0

W aplikacji musi następować jakiś wyciek pamięci. Zwiększanie limitu pamięci nie rozwiąże problemu. Jak możesz to podaj skrypt, który może wywoływać potencjalny problem.

Wcale nie musi następować wyciek pamięci - skrypt może być zwyczajnie pamięciożerny by design ;-) - Patryk27 2018-12-23 23:03

Pozostało 580 znaków

2018-12-23 22:41
0
<?php
    // error_reporting(E_ALL ^ E_WARNING);
    include 'settings.php';

/*  
    $usr = "";
    $pass = "";
    $dbName = ""; //set as unique dbName
    $ip = "localhost";

    $connection = null;
    $debugMode = TRUE; // TRUE: printWrongQueries; FALSE: doNotPrintThem
    $wrongQuery = "";

    $isConnected = FALSE;

    //$port = "3306";

FUNCTION USAGE EXPLANATION:

    =================
    0 parameter functions:
        connectTo():                            starts MySQL connection with config data
        closeConnection():                      closes the connection
        printWrongQuery():                      if $debugMode is TRUE, prints last wrongQuery SQL code
        init():                                 creates database, tables, views and inserts constant data

    =================
    1 parameter functions:
        executeQuery(queryCode):                returns query result or FALSE if failure
        hasRows(queryResult):                   returns TRUE if result has rows, or FALSE if it hasn't
        doesDbExist(db):                        returns TRUE if there is such database, or FALSE if isn't
        doesTableExist(table):                  returns TRUE if there is such table in current DB, or FALSE if 
                                                isn't
        createDb(db):                           creates a db if it is possible
        changeTableIntoStringWithCommas(array): creates string with array elements separated by commas
        changeTableIntoStringWithCommasAndQuotes(array): creates string with array elements in quotes separated 
                                                         by commas
        changeTableIntoStringWithAnd(array):    creates string with array elements separated by ' AND ' phrase
        useDb(db):                              switches active database to db

    =================
    multi-parameter functions:
        createTable(name, col1 properties [, col2 properties, [, ...]]):
                                                creates table with selected name and columns properties list
        createOrReplaceView(table, col1Name [, col2Name [, ...]]):
                                                creates or replaces a view on selected table name
        insertRecordIntoTableIfNotExist(table, val1 [, val2 [, ...]]):
                                                inserts a new record into table, if there is no such record

*/

    function connectTo()
    {
        global $usr;
        global $pass;
        global $dbName;
        global $ip;
        global $connection;
        global $isConnected;

        if ($isConnected == TRUE)
            return TRUE;

        $connection = new mysqli($ip, $usr, $pass, ""); // empty dbName

        if (mysqli_connect_errno())
            exit("Błąd połączenia z bazą:<br>Kod błędu: " . mysqli_connect_errno() . json_encode($connection) ."<br>");

        $isConnected = TRUE;
        $connection->query("SET NAMES 'utf8'");
        $connection->query("SET NAMES `utf8` COLLATE `utf8_polish_ci`");

        return TRUE;
    }

    function closeConnection()
    {
        global $isConnected;
        global $connection;

        if ($isConnected == TRUE)
            if ($connection->close() == FALSE)
            {
                $isConnected = FALSE;

                exit("Błąd rozłączenia<br>");
            }
    }

    function executeQuery($query)
    {
        connectTo();

        global $debugMode;
        global $wrongQuery;
        global $connection;
        global $dbName;

        useDb($dbName);

        $result = $connection->query($query);

        if ($result == FALSE && $debugMode == TRUE)
            $wrongQuery = "Błąd w zapytaniu: " . $query . "<br>";

        return $result;
    }

    function executeMultiQuery($multiQuery)
    {
        connectTo();

        global $debugMode;
        global $wrongQuery;
        global $connection;
        global $dbName;

        useDb($dbName);

        $result = $connection->multi_query($multiQuery);

        if ($result == FALSE && $debugMode == TRUE)
            $wrongQuery = "Błąd w zapytaniu: " . $multiQuery . "<br>";

        return $result;
    }

    function useDb($db)
    {
        $result = executeQuery("USE " . $db . ";");

        if($result == FALSE)
        {
            printWrongQuery();

            exit("Błąd w funckji useDb()<br>");
        }

        //$result->close();
    }

    function printWrongQuery()
    {
        global $debugMode, $wrongQuery;

        if ($debugMode == TRUE)
            echo $wrongQuery;
    }

    function hasRows($table)
    {
        connectTo();

        if ($table->num_rows > 0)
            return TRUE;

        return FALSE;
    }

    function doesDbExist($db)
    {
        $result = executeQuery("SHOW DATABASES LIKE '" . $db . "';");

        if ($result == FALSE)
        {
            // $result->close();
            return FALSE;
        }

        else if (hasRows($result))
        {
            // $result->close();
            return TRUE;
        }

        else
        {
            // $result->close();
            return FALSE;
        }
    }

    function doesTableExist($table)
    {
        $result = executeQuery("SHOW TABLES LIKE '" . $table . "';");

        if ($result == FALSE)
        {
            // $result->close();
            return FALSE;
        }

        else if (hasRows($result))
        {
            // $result->close();
            return TRUE;
        }

        else
        {
            // $result->close();
            return FALSE;
        }
    }

    function createDb($db)
    {
        if (doesDbExist($db) == FALSE)
        {
            $result = executeQuery("CREATE DATABASE " . $db . ";");

            if ($result == FALSE)
            {
                printWrongQuery();

                exit("Wystąpił błąd podczas tworzenia nowej bazy<br>");
            }

            // $result->close();
        }
    }

    function changeTableIntoStringWithCommas($table)
    {
        if (count($table) == 0)
            return "";

        $result = "";

        foreach ($table as $val)
            $result .= $val . ", ";

        $result = substr($result, 0, strlen($result) - 2);

        return $result;
    }

    function changeTableIntoStringWithCommasAndQuotes($table)
    {
        if (count($table) == 0)
            return "";

        $result = "";

        foreach ($table as $val)
            $result .= "'" . $val . "', ";

        $result = substr($result, 0, strlen($result) - 2);

        return $result;
    }

    function changeTableIntoStringWithAnd($table)
    {
        if (count($table) == 0)
            return "";

        $result = "";

        foreach ($table as $val)
            $result .= $val . " AND ";

        $result = substr($result, 0, strlen($result) - 5);

        return $result;
    }

    function createTable() // various number of parameters: 
    // tableName, field1, field2, field3, ...
    {
        if (func_num_args() < 2)
            exit("Błędna liczba parametrów funkcji createTable()<br>");

        $str = changeTableIntoStringWithCommas(func_get_args());
        $firstComma = strpos($str, ",");

        $tableName = substr($str, 0, $firstComma);
        $rest = substr($str, $firstComma + 1);

        if (doesTableExist($tableName) == FALSE)
        {
            $result = executeQuery("CREATE TABLE " . $tableName . " (" . $rest . ");");

            if ($result == FALSE)
            {
                printWrongQuery();

                exit("Błąd tworzenia tabeli<br>");
            }

            $result->close();
        }
    }

    /*
    function doesRecordExist()
    {
        if (func_num_args() < 2)
            exit("Błędna liczba parametrów funkcji doesRecordExist()<br>");

        $str = changeTableIntoStringWithAnd(func_get_args());
        $firstAnd = strpos($str, " AND ");

        $tableName = substr($str, 0, $firstAnd);
        $rest = substr($str, $firstAnd + 5);

        $result = executeQuery("SELECT EXISTS(SELECT * FROM " . $tableName . " WHERE " . $rest . ");");

        if ($result == FALSE)
            return FALSE;

        else if (hasRows($result))
            return TRUE;

        else
            return FALSE;
    }
    */

    function insertRecordIntoTableIfNotExist()
    {
        if (func_num_args() < 2)
            exit("Błędna liczba parametrów funkcji insertRecordIntoTableIfNotExist()<br>");

        $str = changeTableIntoStringWithCommasAndQuotes(func_get_args());
        $firstComma = strpos($str, ",");

        $tableName = substr($str, 0, $firstComma);
        $tableName = substr($tableName, 1, strlen($tableName) - 2);
        $rest = substr($str, $firstComma + 1);

        $result = executeQuery("SELECT " . $rest . " MINUS SELECT * FROM " . $tableName . "_v;");

        if ($result != FALSE)
            if (hasRows($result))
            {
                // $result->close();

                return;
            }

        $result = executeQuery("INSERT INTO " . $tableName . " VALUES(NULL, " . $rest . ");");

        if ($result == FALSE)
        {
            printWrongQuery();

            exit("Błąd podczas dodawania nowego rekordu w funkcji insertRecordIntoTableIfNotExist()<br>");
        }

        // $result->close();
    }

    function createOrReplaceView()
    {
        if (func_num_args() < 3)
            exit("Błędna liczba parametrów funkcji createOrReplaceView()<br>");

        $str = changeTableIntoStringWithCommas(func_get_args());
        $firstComma = strpos($str, ",");

        $tableName = substr($str, 0, $firstComma);
        $rest = substr($str, $firstComma + 1);

        $result = executeQuery("CREATE OR REPLACE VIEW " . $tableName . "_v " . " AS SELECT " . $rest . " FROM " . $tableName . ";");

        if ($result == FALSE)
        {
            printWrongQuery();

            exit("Błąd przy tworzeniu widoku w funkcji createOrReplaceView()<br>");
        }

        // $result->close();
    }

    function printHeaderRowOfTable($table)
    {
        echo "<tr>";

        for ($i = 1; $i < count($table); $i++)
            echo "<td>" . $table[$i] . "</td>";

        echo "</tr>";
    }

    function printTable()
    {
        global $connection;

        if (func_num_args() < 2)
            exit("Błędna liczba parametrów funkcji printTable()<br>");

        $result = func_get_arg(0);

        if ($result != FALSE)
        {
            if ($connection->field_count + 1 != func_num_args())
                exit("Błędna liczba parametrów funkcji printTable()<br>");

            echo "<table>";
            printHeaderRowOfTable(func_get_args());

            while ($row = $result->fetch_row())
            {
                echo "<tr>";

                foreach ($row as $field)
                    echo "<td>" . $field . "</td>";

                echo "</tr>";
            }

            echo "</table>";

            // $result->close();
        }

        else
            exit("Wystąpił błąd w funkcji printTable() - nieprawidłowe zapytanie<br>");
    }

    function init()
    {
        global $dbName;

        echo " 1 ";

        createDb($dbName);

        echo " 2 ";
        useDb($dbName);

        echo " 3 ";

        createTable("movies", // table name changed from 'movieTitles' to 'movies'
            "id INT(6) AUTO_INCREMENT PRIMARY KEY NOT NULL",
            "title VARCHAR(255) NOT NULL",
            "producer int NOT NULL",
            "director int NOT NULL",
            "country int NOT NULL",
            "dateOfProd smallint NOT NULL",
            "duration int NOT NULL",
            "TV tinyint NOT NULL",
            "cinema tinyint NOT NULL",
            "DVD tinyint NOT NULL",
            "VOD tinyint NOT NULL",
            "otherThanCinema tinyint NOT NULL",
            "contractDate DATE NOT NULL",
            "company int NOT NULL",
            "UNIQUE (title)");

        echo " 3 ";

        createTable("producers",
            "id INT AUTO_INCREMENT PRIMARY KEY NOT NULL",
            "name VARCHAR(255) NOT NULL");

        createTable("directors",
            "id INT AUTO_INCREMENT PRIMARY KEY NOT NULL",
            "nameAndSurname VARCHAR(255) NOT NULL");

        createTable("countries",
            "id INT AUTO_INCREMENT PRIMARY KEY NOT NULL",
            "country VARCHAR(255) NOT NULL",
            "taxAtSource TINYINT NOT NULL");

        createTable("companies",
                "id INT AUTO_INCREMENT PRIMARY KEY NOT NULL",
                "name VARCHAR(255) NOT NULL");

        createTable("cinemas",
                "id INT AUTO_INCREMENT PRIMARY KEY NOT NULL",
                "name VARCHAR(255) NOT NULL",
                "city int NOT NULL");

        createTable("cities",
                "id INT AUTO_INCREMENT PRIMARY KEY NOT NULL",
                "name VARCHAR(255) NOT NULL");

        createTable("shows",
                "id INT AUTO_INCREMENT PRIMARY KEY NOT NULL",
                "dateFrom DATE NOT NULL",
                "dateTo DATE NOT NULL",
                "cinema int NOT NULL",
                "title int NOT NULL",
                "setId int NOT NULL",
                "comments VARCHAR(255) NOT NULL",
                "invoice int NOT NULL");

        createTable("sets",
                "id INT AUTO_INCREMENT PRIMARY KEY NOT NULL",
                "name VARCHAR(255) NOT NULL",
                "amount decimal(9, 2) NOT NULL");

        createTable("invoices",
                "id INT AUTO_INCREMENT PRIMARY KEY NOT NULL",
                "number VARCHAR(255) NOT NULL",
                "company int NOT NULL",
                "amount decimal(9, 2) NOT NULL");

        $countries = array(
            array("Albania", "5"),
            array("Algieria", "10"),
            array("Arabia Saudyjska", "10"),
            array("Armenia", "10"),
            array("Australia", "10"),
            array("Austria", "5"),
            array("Azerbejdżan", "10"),
            array("Bangladesz", "10"),
            array("Belgia", "5"),
            array("Białoruś", "0"),
            array("Bośnia i Hercegowina", "20"),
            array("Bułgaria", "5"),
            array("Chile", "15"),
            array("Chiny", "10"),
            array("Chorwacja", "10"),
            array("Cypr", "5"),
            array("Czarnogóra", "10"),
            array("Czeska Republika", "10"),
            array("Dania", "5"),
            array("Egipt", "12"),
            array("Estonia", "10"),
            array("Etiopia", "10"),
            array("Filipiny", "15"),
            array("Finlandia", "5"),
            array("Francja", "0"),
            array("Grecja", "10"),
            array("Gruzja", "8"),
            array("Guernsey", "20"),
            array("Hiszpania", "10"),
            array("Holandia", "5"),
            array("Indie", "15"),
            array("Indonezja", "10"),
            array("Iran", "10"),
            array("Irlandia", "10"),
            array("Islandia", "10"),
            array("Izrael", "10"),
            array("Japonia", "0"),
            array("Jersey", "20"),
            array("Jordania", "10"),
            array("Kanada", "5"),
            array("Katar", "5"),
            array("Kazachstan", "10"),
            array("Kirgistan", "10"),
            array("Korea Płd.", "5"),
            array("Kuwejt", "15"),
            array("Liban", "5"),
            array("Litwa", "10"),
            array("Luksemburg", "5"),
            array("Łotwa", "10"),
            array("Macedonia", "10"),
            array("Malezja", "8"),
            array("Malta", "5"),
            array("Maroko", "10"),
            array("Meksyk", "10"),
            array("Mołdawia", "10"),
            array("Mongolia", "5"),
            array("Niemcy", "5"),
            array("Nigeria", "10"),
            array("Norwegia", "5"),
            array("Nowa Zelandia", "10"),
            array("Pakistan", "20"),
            array("Polska", "0"),
            array("Portugalia", "10"),
            array("Republika Płd. Afryki", "10"),
            array("Rosja", "10"),
            array("Rumunia", "10"),
            array("Serbia", "10"),
            array("Singapur", "5"),
            array("Słowacka Rep.", "5"),
            array("Słowenia", "10"),
            array("SriLanka", "10"),
            array("Stany Zjednoczone", "5"),
            array("Syria", "18"),
            array("Szwajcaria", "0"),
            array("Szwecja", "5"),
            array("Tadżykistan", "10"),
            array("Tajlandia", "15"),
            array("Tunezja", "12"),
            array("Turcja", "10"),
            array("Ukraina", "10"),
            array("Urugwaj", "15"),
            array("Uzbekistan", "10"),
            array("Węgry", "10"),
            array("Wielka Brytania", "5"),
            array("Wietnam", "15"),
            array("Włochy", "10"),
            array("Wyspa Man", "20"),
            array("Zambia", "10"),
            array("Zjedn. Emiraty Arabskie", "5"),
            array("Zimbabwe", "10"),
            array("inne", "20"));

        foreach ($countries as $val)
            insertRecordIntoTableIfNotExist("countries", $val[0], $val[1]);

        $files = scandir("./queries");

        foreach ($files as $fileName)
            if ($fileName != "." && $fileName != "..")
                executeMultiQuery(file_get_contents("./queries/" . $fileName));
    }
?>

Wywołuję z zewnątrz funkcję init(). Wywala się po echo " 1 ";

Wywołuję stąd:

<?php
    function createUserAndDb($connection)
    {
        $result = $connection->query("CREATE USER '" . $_REQUEST["usr"] . "'@'" . $_REQUEST["addr"] . "';");

        if ($result != FALSE)
        {
            echo "dodano użytkownika<br>";

            //$result->close();
            $result = $connection->query("CREATE DATABASE " . $_REQUEST["db"] . " DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;");

            if ($result != FALSE)
            {
                echo "stworzono bazę<br>";

                //$result->close();
                $result = $connection->query("GRANT ALL PRIVILEGES ON " . $_REQUEST["db"] . ".* To '" . $_REQUEST["usr"] . "'@'" . $_REQUEST["addr"] . "' IDENTIFIED BY '" . $_REQUEST["pass"] ."'");

                if ($result != FALSE)
                {
                    echo "nadano uprawnienia<br>";

                    return TRUE;
                }
            }
        }

        return FALSE;
    }

    $connection2 = new mysqli($_REQUEST["addr"], $_REQUEST["usrRoot"], $_REQUEST["passRoot"], "");

    $newSettingsFileString = sprintf(file_get_contents("settings_install.php"), 
        $_REQUEST["usr"], $_REQUEST["pass"], $_REQUEST["db"], $_REQUEST["addr"]);

    if (createUserAndDb($connection2) == FALSE)
        echo "Błąd podczas dodawania użytkownika lub bazy";

    else
    {
        file_put_contents("settings.php", $newSettingsFileString);

        include "akomodacja.php";
        $connection2->close();

        init();
        echo "OK1234";
    }
?>
edytowany 1x, ostatnio: mpaw, 2018-12-23 22:46
Whoa - 95% tego kodu jest wynajdywaniem koła na nowo :-P - Patryk27 2018-12-23 23:00

Pozostało 580 znaków

2018-12-23 23:06

Która konkretnie linijka powoduje problem + jak wygląda backtrace + co mówi xdebug?

Czy jest możliwe że serwer cache'uje wyniki zapytań i przepełnił mu się licznik?

Który licznik miałby się przepełniać?

Btw, jeśli piszesz ten skrypt w celach edukacyjnych to jeszcze da radę, natomiast staraj się nie wynajdywać koła na nowo - istnieją już setki gotowych, przetestowanych i stabilnych bibliotek ułatwiających pracę na bazie danych (począwszy od tych prostszych po Doctrine'a) dzięki którym nie będziesz tracił dużo czasu na pisanie boilerplate'owego kodu + późniejsze jego debuggowanie ;-)


edytowany 3x, ostatnio: Patryk27, 2018-12-23 23:08
Dziękuję. Odpiszę Jutro, bo już późno, dobranoc. - mpaw 2018-12-23 23:20

Pozostało 580 znaków

2018-12-24 10:24
1

Bardzo dziękuję za pomoc. Już się wyjaśniło. Zainstalowałem XDebug i okazało się, że miałem zagnieżdżone wywołanie funkcji useDB i executeQuery jedna korzystała z drugiej i vice versa. Dzięki!

    function executeQuery($query)
    {
        connectTo();

        global $debugMode;
        global $wrongQuery;
        global $connection;
        global $dbName;

        useDb($dbName); //TU

        $result = $connection->query($query);

        if ($result == FALSE && $debugMode == TRUE)
            $wrongQuery = "Błąd w zapytaniu: " . $query . "<br>";

        return $result;
    }

    function useDb($db)
    {
        $result = executeQuery("USE " . $db . ";"); //I TU

        if($result == FALSE)
        {
            printWrongQuery();

            exit("Błąd w funckji useDb()<br>");
        }

        //$result->close();
    }
edytowany 1x, ostatnio: mpaw, 2018-12-24 10:25

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0