Dùng Xdebug để kiểm tra lỗi “PHP Fatal Error: Allowed memory size”

Chào các bạn,

Bài viết hôm nay sẽ chia sẻ một số kinh nghiệm của mình khi kiểm tra và xử lý lỗi “PHP Fatal Error: Allowed memory size”

Nguyên nhân gây ra lỗi 

Trong quá trình hoạt động hoặc khi deploy mã nguồn lên Hosting mới, chúng ta thỉnh thoảng gặp phải lỗi “PHP Fatal Error: Allowed memory size”, nguyên nhân dẫn tới lỗi này thường do mã nguồn yêu cầu dung lượng Memory nhiều hơn giới hạn PHP của Hosting mà bạn đang sử dụng hoặc một vài function() bị LOOP dẫn tới PHP tạo thêm vùng nhớ liên tục mà không kiểm soát được. Bài viết hôm nay sẽ hướng dẫn các bạn khắc phục các vấn đề này.

Cách kiểm tra và xử lý

Để bắt đầu kiểm tra vấn đề, đầu tiên chúng ta phải xem được Error log của PHP để xem được vấn đề xuất phát từ đâu. Các mã nguồn phổ biến như WordPress, Joomla, Xenforo sẽ có thông báo ngay cho chúng ta nếu như mức giới hạn Memory không đáp ứng được Requirement của nhà phát triển, khi đó chỉ cần cấu hình lại mức limit đúng với Requirement thì mọi chuyện sẽ được giải quyết.

Thực hiện tăng PHP Memory Limit lên như sau, edit file php.ini:

memory_limit = 256M

Thực hiện restart HTTPD, nếu vẫn báo lỗi có thể tiếp tục tăng và thử lại. Tuy nhiên nếu đã tăng quá mức 512MB mà vẫn bị lỗi này, chúng ta sẽ cần dùng Xdebug để kiểm tra lỗi. Hosting của 123HOST đã được cài sẵn Xdebug, các bạn chỉ cần vào PHP Selector và enable lên là dùng được. Nếu chạy trên server hoặc VPS chưa có sẵn Xdebug, chúng ta thực hiện cài Xdebug như sau:

PHP > 7.0

pecl install xdebug

Thêm đường dẫn extension vào file php.ini

zend_extension="/usr/local/php/modules/xdebug.so"

PHP < 5.6

wget https://xdebug.org/files/xdebug-2.5.5.tgz
tar -xvzf xdebug-2.5.5.tgz
cd xdebug-2.5.5
phpize
./configure
make && make install

Thêm đường dẫn extension vào file php.ini

extension=xdebug.so

Kiểm tra Xdebug cài đặt thành công bằng lệnh

php -m | grep xdebug

Hoặc xem bằng phpinfo();

Sau khi cài đặt thành công Xdebug, các bạn quay trở lại với đường dẫn bị lỗi để xem stack_trace của Xdebug, các bạn có thể thêm vào các giá trị sau trong index.php hoặc file php nào sẽ thực thi request để Xdebug show cho chúng ta nhiều thông tin hơn:

ini_set('xdebug.collect_vars', 'on'); // Thu thập toàn bộ các varaible() nào được gọi tới trong quá trình execute PHP script
ini_set('xdebug.collect_params', '4'); // Hỗ trợ cho biến trên, hiển thị varaible name và varaible content
ini_set('xdebug.dump_globals', 'on'); // Giúp dump toàn bộ các giá trị COOKIE, FILES, GET, POST, REQUEST, SERVER, SESSION mà server nhận được nếu có
ini_set('xdebug.dump.SERVER', 'REQUEST_URI'); // Hiển thị URL đang truy cập
ini_set('xdebug.show_local_vars', 'on');

Sau khi truy cập lại đường dẫn lỗi với Xdebug được kích hoạt, chúng ta thấy một lỗi khác xuất hiện trên thanh cảnh báo thay cho lỗi “PHP Fatal Error: Allowed memory size” trước đó.

“Maximum function nesting level of ‘256’ reached”

xdebug.max_nesting_level=256

Đây là một cơ chế của Xdebug để phát hiện và ngăn chặn Infinite Recursion. Xdebug sẽ quy định số lần thực hiện nested functions – function() gọi đến 1 function() khác, nếu vượt quá số lần quy định, toàn bộ Operation sẽ bị hủy bỏ và hiển thị thông báo lỗi như trên.

Tới đây chúng ta đã biết được nguyên nhân gây ra Infinitie Loop là do handle404( $cat = ??? ) <—> display( $tpl = ??? ). Tùy vào hoàn cảnh mà lỗi của bạn có thể khác chứ không nhất thiết sẽ giống như trong ví dụ trên, nhưng về cơ bản, bạn sẽ được show ra một màn hình lỗi dài ngoằn, tới đây là chún ta đã đi được 50% đoạn đường. Khi có thông tin về các function() gây ra Infinitie Loop, chúng ta tiếp tục phân tích chức năng và cách hoạt động của các function() này để tìm điều kiện cho chương trình thoát Loop.

view.html.php:322
if ((int)VmConfig::get('handle_404',1)) {
		        header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");

			$cat = VmModel::getModel('category')->getCategory($last_category_id);
			if(empty($cat->virtuemart_category_id)){
				$last_category_id = 0;
			}
			vRequest::setVar('virtuemart_category_id', $last_category_id);
			$this->display();
		} else {
			throw new RuntimeException('VirtueMart category not found.', 404);
		}
view.html.php:683
if ((!empty($this->categoryId) and $this->categoryId!==-1 ) and (empty($category->slug) or !$category->published)) {

		$this->handle404();
	}

Xem qua 2 đoạn code trên cho thấy chức năng đang bị lỗi là chức năng Ridirect 404 cho sản phẩm của Virtuemart. Chúng ta thực hiện login vào admin của Joomla và tìm đến chức năng Redirect 404 của Virtuemart và tắt nó đi.

Kết luận

Lỗi “PHP Fatal Error: Allowed memory size” rất đa dạng nguyên nhân, Xdebug chỉ giúp chúng ta phát hiện nguyên nhân qua cơ chế Nesting Level, việc khắc phục được lỗi sẽ còn phụ thuộc vào quá trình tìm hiểu cơ chế hoạt động của các function() gây ra lỗi. Hy vọng bài viết này sẽ giúp các bạn xử lý được vấn đề đang gặp phải.

Peace out!

 

Rate This Article

Leave A Comment?