本文介绍了PHP mysql_stmt :: fetch()给PHP致命错误内存耗尽的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! CentOS 6.4 PHP 5.3.3 MySQL 5.1.69 x86_64 $ b $ b 这个问题有两个: 与局部变量,MySQL 用户变量支持一组非常有限的数据类型:文档未提及实际数据类型 used分别为 BIGINT , DECIMAL(65,30), DOUBLE , LONGBLOB , LONGTEXT 和 LONGBLOB 。关于最后一个,手册至少解释: Storage 分别需要8,30和8个字节。其他数据类型(即对于字符串和 NULL 值)需要(最多) 4千兆字节的存储空间。 由于您使用的版本是v5.4.0之前的版本,因此默认的MySQL驱动程序为 libmysql ,在数据绑定时,只有列类型元数据可以从服务器获得;因此MySQLi尝试分配足够的内存来保存每个可能的值(即使整个缓冲区不是最终需要);因此 NULL - 和字符串值用户变量,其最大可能大小为4GiB,导致PHP超过其默认内存限制(自PHP v5.2.0起为128MiB)。 您的选项包括: 覆盖表定义中的列数据类型: DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table( status VARCHAR(2))SELECT @status AS status; 明确将用户变量转换为更具体的数据类型: DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table SELECT CAST(@status AS CHAR(2))AS状态; 使用以明确数据类型声明的局部变量: DECLARE status VARCHAR(2)DEFAULT @status; DROP TEMPORARY TABLE IF EXISTS tmp_table; CREATE TEMPORARY TABLE tmp_table SELECT status;通过调用 mysqli_stmt :: store_result()来解决这个问题, 之前 mysqli_stmt :: bind_result(),这导致结果集存储在libmysql(PHP的内存限制之外),然后PHP将只分配所需的实际内存在抓取记录时保存记录: $ stmt-> execute() $ stmt-> store_result(); $ stmt-> bind_result($ status); $ stmt-> fetch() 提高PHP的内存限制,以便它可以适应4GiB缓冲区的分配(虽然应该意识到这样做对硬件资源的影响)—例如,为了完全消除内存限制(虽然意识到潜在的负面影响,例如从真正的内存泄漏): ini_set('memory_limit','-1'); 重新编译PHP,并配置为使用本机mysqlnd驱动程序(自v5.3.0起包含在PHP中,但未配置为默认,直到PHP v5.4.0)而不是libmysql: ./ configure --with-mysqli = mysqlnd 升级到PHP v5.4.0或更高版本,以便默认使用mysqlnd。 CentOS 6.4 PHP 5.3.3 MySQL 5.1.69 x86_64mysql_stmt::fetch()When executing fetch using a prepared statement, PHP yields error: PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 4294967296 bytes).This occurs when a variable included in a SELECT statement used to create a temporary table is unset, whether or not the variable is otherwise set in the environment before the stored procedure is called. The variable must be set within the stored procedure. When a SELECT statement is used to return data in the temporary table to PHP, and PHP uses mysql_stmt::fetch() to access the data, PHP generates the above fatal error.MySQL Code:DELIMITER $$CREATE PROCEDURE test_sp()BEGIN # uncomment below line, and PHP call to mysqli_stmt::fetch() works # SET @status = 1; # remove tmp table DROP TABLE IF EXISTS tmp_table; # CREATE TEMPORARY TABLE CREATE TEMPORARY TABLE tmp_table SELECT @status AS status; SELECT * FROM tmp_table;END $$DELIMITER ;PHP Code:// obtain MySQL login inforequire_once(MYSQLOBJ);// initialize status$status = "";$db = new mysqli( DB_HOST, DB_USER, DB_PASSWORD, DB_NAME );$query = "CALL test_sp";$stmt = $db->prepare($query);$stmt->execute();$stmt->bind_result( $status );$stmt->store_result();$stmt->fetch(); // PHP FATAL ERROR OCCURS HERE$stmt->free_result();$db->close();print "<p>status = $status</p>\n"; 解决方案 You will find that this is occurring only when @status is NULL or a string.The problem is twofold:Unlike local variables, MySQL user variables support a very limited set of datatypes:The documentation fails to mention that the actual datatypes used are respectively BIGINT, DECIMAL(65,30), DOUBLE, LONGBLOB, LONGTEXT and LONGBLOB. Regarding the last one, the manual does at least explain:Storage of the first three of these datatypes (i.e. for integer, decimal and floating-point values) require 8, 30 and 8 bytes respectively. The other datatypes (i.e. for string and NULL values) require (up to) 4 gigabytes of storage.Since you are using a version of PHP prior to v5.4.0, the default MySQL driver is libmysql, with which only column type metadata is available from the server upon data binding—so MySQLi attempts to allocate sufficient memory to hold every possible value (even if the full buffer is not ultimately required); thus NULL- and string-valued user variables, which have a maximum possible size of 4GiB, cause PHP to exceed its default memory limit (of 128MiB since PHP v5.2.0).Your options include:Overriding the column datatype in the table definition:DROP TEMPORARY TABLE IF EXISTS tmp_table;CREATE TEMPORARY TABLE tmp_table ( status VARCHAR(2)) SELECT @status AS status;Explicitly casting the user variable to a more specific datatype:DROP TEMPORARY TABLE IF EXISTS tmp_table;CREATE TEMPORARY TABLE tmp_table SELECT CAST(@status AS CHAR(2)) AS status;Using local variables, which are declared with an explicit datatype:DECLARE status VARCHAR(2) DEFAULT @status;DROP TEMPORARY TABLE IF EXISTS tmp_table;CREATE TEMPORARY TABLE tmp_table SELECT status;Working around the issue by calling mysqli_stmt::store_result() before mysqli_stmt::bind_result(), which causes the resultset to be stored in libmysql (outside of PHP's memory limits) and then PHP will only allocate the actual memory required to hold the record upon fetching it:$stmt->execute();$stmt->store_result();$stmt->bind_result( $status );$stmt->fetch();Raising PHP's memory limit so that it can accomodate the allocation of 4GiB buffers (although one should be aware of the implications on hardware resources from doing so)—for example, to remove the memory constraints entirely (although be aware of potential negative side-effects from doing this, e.g. from genuine memory leaks):ini_set('memory_limit', '-1');Recompiling PHP, configured to use the native mysqlnd driver (included with PHP since v5.3.0, but not configured as the default until PHP v5.4.0) instead of libmysql:./configure --with-mysqli=mysqlndUpgrading to PHP v5.4.0 or later so that mysqlnd is used by default. 这篇关于PHP mysql_stmt :: fetch()给PHP致命错误内存耗尽的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
08-24 15:07
查看更多