3 дня разбился головой о стену.
Я разработал php-скрипт для импорта больших текстовых файлов и заполнения базы данных mysql. Пока я не получу 2 миллиона записей, он работает отлично, но мне нужно импортировать около 10 миллионов строк, разделенных на разные файлы.
Мое приложение сканирует файлы в папке, получает расширение файла (у меня есть 4 вида импорта процедур для 4 разных расширений) и вызывает функцию относительного импорта.
У меня есть структура из этих классов:
CLASS SUBJECT1{ public function import_data_1(){
__DESTRUCT(){$this->childObject = null;}
IMPORT SUBJECT1(){
//fopen($file);
//ob_start();
//PDO::BeginTransaction();
//WHILE (FILE) {
//PREPARED STATEMENT
//FILE READING
//GET FILE LINE
//EXECUTE INSERT
//} END WHILE
//PDO::Commit();
//ob_clean(); or ob_flush();
//fclose($file);
//clearstatcache();
}
};}
CLASS SUBJECT2{ same as SUBJECT1;}
CLASS SUBJECT3{ same as SUBJECT1;}
CLASS SUBJECT4{ same as SUBJECT1;}
и основной класс, запускающий процедуру:
CLASS MAIN{
switch($ext)
case "ext1":
$SUBJECT1 = new SUBJECT1();
IMPORT_SUBJECT1();
unset $SUBJECT1;
$SUBJECT1 = null;
break;
case "ext2": //SAME AS CASE ext1 WITH IMPORT_SUBJECT2();
case "ext3": //SAME AS CASE ext1 WITH IMPORT_SUBJECT3();
case "ext4": //SAME AS CASE ext1 WITH IMPORT_SUBJECT4();
}
Он отлично работает с некоторой настройкой файловых буферов mysql (ib_logfile0 и ib_logfile1 установлены как 512 МБ).
Проблема в том, что каждый раз, когда процедура завершается, php не освобождает память. Я уверен, что вызывается деструктор (я помещаю эхо в метод __destruct), и объект недоступен (var_dump говорит, что это NULL). Я пробовал так много способов освободить память, но теперь я в мертвой точке.
Я также проверил gc_collect_cycles () во многих разных точках кода, и он всегда говорит 0 циклов, поэтому все abject не ссылаются друг на друга. Я пытался даже удалить структуру классов и вызвать весь код последовательно, но всегда получаю такую ошибку:
Неустранимая ошибка: недостаточно памяти (выделено 511180800) (попытка выделить 576 байт) в C: \ php \ index.php в строке 219 (строка 219 выполняет PS в 13-м файле).
Память используется таким образом:
- php скрипт: 52 МБ
- конец первого импорта файла: 110 МБ
- деструкторы и вызов unset: 110 МБ
- вызов новой процедуры: 110 МБ
- конец импорта второго файла 250 МБ
- деструкторы и вызов unset: 250 МБ
- вызов новой процедуры: 250 МБ
Итак, как вы можете видеть, даже сбрасывая объекты, они не освобождают память.
Я попытался установить размер памяти php ini на 1024 МБ, но он очень быстро растет и вылетает после 20 файлов.
Любой совет?
Большое спасибо!
РЕДАКТИРОВАТЬ 1:
почтовый индекс:
class SUBJECT1{
public function __destruct()
{
echo 'destroying subject1 <br/>';
}
public function import_subject1($file,$par1,$par2){
global $pdo;
$aux = new AUX();
$log = new LOG();
// ---------------- FILES ----------------
$input_file = fopen($file, "r");
// ---------------- PREPARED STATEMENT ----------------
$PS_insert_data1= $pdo->prepare("INSERT INTO table (ID,PAR1,PAR2,PARN) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE ID = VALUES(ID), PAR1 = VALUES(PAR1), PAR2 = VALUES(PAR2), PAR3 = VALUES(PAR3), PARN = VALUES(PARN)");
$PS_insert_data2= $pdo->prepare("INSERT INTO table (ID,PAR1,PAR2,PARN) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE ID = VALUES(ID), PAR1 = VALUES(PAR1), PAR2 = VALUES(PAR2), PAR3 = VALUES(PAR3), PARN = VALUES(PARN)");
//IMPORT
if ($input_file) {
ob_start();
$pdo->beginTransaction();
while (($line = fgets($input_file)) !== false) {
$line = utf8_encode($line);
$array_line = explode("|", $line);
//set null values where i neeed
$array_line = $aux->null_value($array_line);
if(sizeof($array_line)>32){
if(!empty($array_line[25])){
$PS_insert_data1->execute($array_line[0],$array_line[1],$array_line[2],$array_line[5]);
}
$PS_insert_data2->execute($array_line[10],$array_line[11],$array_line[12],$array_line[15]);
}
$pdo->commit();
flush();
ob_clean();
fclose($f_titolarita);
clearstatcache();
}
Я делаю это итеративно для всех файлов в моей папке, остальные процедуры имеют ту же концепцию. У меня все еще есть увеличение памяти, и теперь он вылетает с ответом белой страницы: - \