首页 > 代码库 > memory_limit的一个bug | 风雪之隅
memory_limit的一个bug | 风雪之隅
27 Nov 09 memory_limit的一个bug <iframe id=I0_1474129998713 title=+1 style="BORDER-TOP: medium none; HEIGHT: 15px; BORDER-RIGHT: medium none; WIDTH: 70px; BORDER-BOTTOM: medium none; POSITION: static; LEFT: 0px; BORDER-LEFT: medium none; TOP: 0px; VISIBILITY: visible" src="https://apis.google.com/se/0/_/+1/fastbutton?usegapi=1&size=small&origin=http%3A%2F%2Fwww.laruence.com&url=http%3A%2F%2Fwww.laruence.com%2F2009%2F11%2F27%2F1164.html&gsrc=3p&ic=1&hostiemode=7&jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.zh_CN.dTJobwyK6iw.O%2Fm%3D__features__%2Fam%3DAQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAGLTcCOxC3Rwfebd0IWQg_H1R-vfmMxv6w#_methods=onPlusOne%2C_ready%2C_close%2C_open%2C_resizeMe%2C_renderstart%2Concircled%2Cdrefresh%2Cerefresh&id=I0_1474129998713&parent=http%3A%2F%2Fwww.laruence.com&pfname=&rpctoken=31652273" frameBorder=0 width="100%" allowTransparency name=I0_1474129998713 scrolling=no frameborder="0" marginheight="0" marginwidth="0" tabindex="0" data-gapiattached="true"></iframe>
- 作者: Laruence( )
- 本文地址: http://www.laruence.com/2009/11/27/1164.html
- 转载请注明出处
PHP 5.2x中, 由于错误的选用了zend_atoi, 导致memory_limit不能设置为超过4G的值.
今天同事分享给我一个问题(thans to yanmi), 一段代码(PHP 5.2.11 Linux/X86_64),设置memory_limit为4096M会导致内存耗尽, 而设置4095M就不会. 奇怪的问题呵.
那是怎么回事呢?
问题的原因也很简单, 在PHPSRC/main.c中定义的memory_limit设置项的处理器OnChangeMemoryLimit中, 并没有检测当前的机器字长, 而统一使用了zend_atoi来做为字符串数字化, 这个问题在PHP5.3的版本中已经修正(换成了zend_atol):
- static PHP_INI_MH(OnChangeMemoryLimit)
- {
- if (new_value) {
- PG(memory_limit) = zend_atoi(new_value, new_value_length);
- } else {
- PG(memory_limit) = 1<<30; /* effectively, no limit */
- }
- return zend_set_memory_limit(PG(memory_limit));
- }
而, 顾名思义么, atoi是转成整形, 4096M是2的32次方, 发生溢出, 继而环绕成结果为0, zend_atoi代码如下:
- ZEND_API int zend_atoi(const char *str, int str_len)
- {
- int retval;
- if (!str_len) {
- str_len = strlen(str);
- }
- retval = strtol(str, NULL, 0);
- if (str_len>0) {
- switch (str[str_len-1]) {
- case ‘g‘:
- case ‘G‘:
- retval *= 1024;
- /* break intentionally missing */
- case ‘m‘:
- case ‘M‘:
- retval *= 1024;
- /* break intentionally missing */
- case ‘k‘:
- case ‘K‘:
- retval *= 1024;
- break;
- }
- }
- return retval;
- }
最后在zend_set_memory_limit的时候, 会错误的设置memory_limit为mm_heap的blok_size, 那结果就肯定远远小与你所预期的4096M了
- ....
- AG(mm_heap)->limit = (memory_limit >= AG(mm_heap)->block_size) ? memory_limit : AG(mm_heap)->block_size;
- ...
最后, 如果是32位的机器, 那确实不算bug, 但现在的机器很多都64了, 最大内存也不再是4GB了, PHP也要与时俱进啊.
PS, 多看别人的代码是有好处的, 今天有学会了intentionally这个单词, ^_^.
<script type=text/javascript src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js"></script><script type=text/javascript src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js"></script><script type=text/javascript src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js"></script>
Related Posts:
Tags: PHP, php bug, php源码分析
memory_limit的一个bug | 风雪之隅