Unfortunately I can not provide the source code of the script and there are only examples when in my opinion there may be a leak.
The php script works in the background, processes everything in several processes work with the processes - there is the main process and it only breeds children for the purpose of processing, the child processes download zip archives from ftp, extracts all xml files from zip and then processes them and writes them to mysql .
And an interesting way to find leaks, the script runs for several days from 1 to 3. After some time, uses all the memory on the server and the server stops responding.
Possible reasons for the leak (simplified version, there are no checks that the file was downloaded, processing xml and sending it to the database and searching for new zip files):
// Скачиваем архив и отправляем путь до файла в функцию, около 430000 zip файлов function start(){ $file_loc = fopen(local_dir.ftp_zip, 'w'); if(@ftp_fget($conn_id, $file_loc, $ftp_zip, FTP_BINARY)) { $this->open_zip(local_dir.$ftp_zip, $link_sql); } unlink(local_dir.ftp_zip); } // Вытаскиваем из zip xml файлы function open_zip($file, $link_sql){ $zip = new ZipArchive; if($zip->open($file) == TRUE) { // Обычно в 1 архиве от 10000 до 100000 xml файлов for($i = 0; $i < $zip->numFiles; $i ++) { $filename_full = $zip->getNameIndex($i); $filename = explode('_', $filename_full)[0]; // Отправляем $xml_text в приватную функцию xml_to_sql($zip->getFromName($filename_full), $link_sql) } } } } // Преобразуем xml в SimpleXMLElement, где $xml_text это строка в формате xml function xml_to_sql($xml_text, $link_sql){ foreach(new SimpleXMLElement($xml_text) as $xml) { break; } } Identity code for child processes:
class daemon_regions { // Список обрабатываемых регионов private $regions = ['dir1', 'dir2', 'dir3']; // Максимальное количество дочерних процессов public $maxProcesses = 10; // Когда установится в TRUE, демон завершит работу protected $stop_server = FALSE; // Здесь будем хранить запущенные дочерние процессы protected $currentJobs = array(); public function __construct() { // Ждем сигналы SIGTERM и SIGCHLD pcntl_signal(SIGTERM, array($this, "childSignalHandler")); pcntl_signal(SIGCHLD, array($this, "childSignalHandler")); } // Родитель плодит детей public function run() { // Пока $stop_server не установится в TRUE, гоняем бесконечный цикл foreach($this->regions as $name) { // Если уже запущено максимальное количество дочерних процессов, ждем их завершения $flud_off = True; while(count($this->currentJobs) >= $this->maxProcesses) { if($flud_off) { $flud_off = False; } sleep(10); } if(!$this->stop_server) { $this->launchJob($name, $settings); } } while($this->currentJobs != []) { sleep(1); } } // Создает дочерний процесс protected function launchJob($name) { // Создаем дочерний процесс // весь код после pcntl_fork() будет выполняться // двумя процессами: родительским и дочерним $pid = pcntl_fork(); if($pid == - 1) { // Не удалось создать дочерний процесс return FALSE; } elseif($pid) { // Этот код выполнится родительским процессом $this->currentJobs[$pid] = TRUE; } else { // А этот код выполнится дочерним процессом $start = time(); $dm = new daemon_region_parser(); $dm->main($name); $today_summ = gmdate("H:i:s", time() - $start); exit(); } return TRUE; } // Обработка получаемых UNIX сигналов public function childSignalHandler($signo, $pid = null, $status = null) { switch ($signo) { case SIGTERM: // При получении сигнала завершения работы устанавливаем флаг $this->stop_server = true; break; case SIGCHLD: // При получении сигнала от дочернего процесса if(!$pid) { $pid = pcntl_waitpid(- 1, $status, WNOHANG); } // Пока есть завершенные дочерние процессы while($pid > 0) { if($pid && isset($this->currentJobs[$pid])) { // Удаляем дочерние процессы из списка unset($this->currentJobs[$pid]); } $pid = pcntl_waitpid(- 1, $status, WNOHANG); } break; default: // все остальные сигналы break; } } } I use php v5.6, mysql and the mysqli module.
About the server: tested on a VPS SMP Debian v3.16.36, 2 cores and 58GB of RAM, and another server running SMP Debian 3.16.36, 12 cores with and 64 GB of RAM.
top, look at what processes are guzzling memory. - rjhdby