Bug #69305 [NEW]: memory leak in json_encode()

From: Date: Thu, 26 Mar 2015 11:16:59 +0000
Subject: Bug #69305 [NEW]: memory leak in json_encode()
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-191614@lists.php.net to get a copy of this message
From: zoopi01 at gmail dot com Operating system: CentOS 5.7 PHP version: 5.4.39 Package: JSON related Bug Type: Bug Bug description:memory leak in json_encode() Description: ------------ A few days ago, my server ran out of memory and hung up. The server is on CentOS 5.7, Apache httpd(prefork) 2.2.22 and PHP 5.4.39. Please see below test code for reproducing the similar situation. After converted the json object into a json string for returning a result, and memory usage of a httpd process was increased over than 160m and remained. (The value of memory_limit in php.ini is 32m.) For investigating this problem, I checked pmap and smaps output. --------------------------------------------- # pmap -x <pid> ... 00002b6c4d374000 9364 8496 8496 rw--- [ anon ] 00002b6c4de76000 160236 154692 154692 rw--- [ anon ] 00007fff5f4b4000 84 44 44 rw--- [ stack ] ... # cat /proc/<pid>/smaps ... 2b6c4de76000-2b6c57af1000 rw-p 2b6c4de76000 00:00 0 Size: 160236 kB Rss: 154692 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 154692 kB Swap: 0 kB Pss: 154692 kB ... --------------------------------------------- And I traced system calls through strace. Many anonymous pages were allocated by mmap() syscall, and munmap() syscall corresponding mmap() weren't called. (I reproduced the situation for debugging, and some addresses are different as before.) --------------------------------------------- # strace -p <pid> | egrep "mmap|mremap|munmap" ... mmap(NULL, 11276288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1307754000 mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b13087f7000 mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b13088f7000 mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b13089f7000 mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1308af7000 mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1308bf7000 mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1308cf7000 mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1308df7000 mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1308ef7000 mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1308ff7000 munmap(0x2b1307754000, 11276288) = 0 mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1307754000 mmap(NULL, 1183744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1307854000 mmap(NULL, 1445888, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1307975000 mmap(NULL, 1708032, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1307ad6000 mmap(NULL, 1970176, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1307c77000 mmap(NULL, 2232320, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1307e58000 mmap(NULL, 2494464, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b13090f7000 mmap(NULL, 2756608, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1309358000 mmap(NULL, 3018752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b13095f9000 mmap(NULL, 3280896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b13098da000 mmap(NULL, 3543040, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1309bfb000 mmap(NULL, 3805184, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b1309f5c000 mmap(NULL, 4067328, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b130a2fd000 mmap(NULL, 4329472, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b130a6de000 mmap(NULL, 4591616, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b130aaff000 mmap(NULL, 4853760, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b130af60000 mmap(NULL, 5115904, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b130b401000 mmap(NULL, 5378048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b130b8e2000 mmap(NULL, 5640192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b130be03000 mmap(NULL, 5902336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b130c364000 mmap(NULL, 6164480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b130c905000 mmap(NULL, 6426624, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2b130cee6000 ... --------------------------------------------- So, I looked into that who allocated that many pages. (I reproduced the situation for debugging, and some addresses are different as before.) --------------------------------------------- ... Catchpoint 1 (call to syscall 'mmap'), 0x00002b8e14b8b0ea in mmap64 () from /lib64/libc.so.6 (gdb) bt #0 0x00002b8e14b8b0ea in mmap64 () from /lib64/libc.so.6 #1 0x00002b8e14b2d9b6 in _int_malloc () from /lib64/libc.so.6 #2 0x00002b8e14b2e6df in _int_realloc () from /lib64/libc.so.6 #3 0x00002b8e14b2f3e2 in realloc () from /lib64/libc.so.6 #4 0x00002b8e1d75ab50 in zend_mm_mem_malloc_realloc (storage=0x2b8e1a762300, ptr=0x2b8e25399030, size=524288) at /root/php-5.4.39/Zend/zend_alloc.c:292 #5 0x00002b8e1d75efd9 in _zend_mm_realloc_int (heap=0x2b8e1a762320, p=0x2b8e25399090, size=261984, __zend_filename=0x2b8e1d8b5428 "/root/php-5.4.39/ext/json/json.c", __zend_lineno=530, __zend_orig_filename=0x0, __zend_orig_lineno at /root/php-5.4.39/Zend/zend_alloc.c:2292 #6 0x00002b8e1d75f7d5 in _erealloc (ptr=0x2b8e25399090, size=261984, allow_failure=0, __zend_filename=0x2b8e1d8b5428 "/root/php-5.4.39/ext/json/json.c", __zend_lineno=530, __zend_orig_filename=0x0, __zend_orig_lineno=0) at /root/php-5.4.39/Zend/zend_alloc.c:2446 #7 0x00002b8e1d5e65d5 in json_escape_string (buf=0x7fff42111ca0, s=0x2b8e1f9c7610 "abcdefg123456한글입니다abcdefg123456한글입니다abcdefg123456한글입니다abcdefg123456한글입니다abcdefg123456한글입니다abcdefg123456한글입니다abcdefg123456한글입니다abcd"..., len=1800, options=0) at /root/php-5.4.39/ext/json/json.c:530 #8 0x00002b8e1d5e25ba in json_encode_array (buf=0x7fff42111ca0, val=0x7fff421114a0, options=0) at /root/php-5.4.39/ext/json/json.c:299 #9 0x00002b8e1d5e8594 in php_json_encode (buf=0x7fff42111ca0, val=0x2b8e1f9c26e0, options=0) at /root/php-5.4.39/ext/json/json.c:642 #10 0x00002b8e1d5e238f in json_encode_array (buf=0x7fff42111ca0, val=0x7fff42111820, options=0) at /root/php-5.4.39/ext/json/json.c:279 #11 0x00002b8e1d5e8594 in php_json_encode (buf=0x7fff42111ca0, val=0x2b8e1f497b60, options=0) at /root/php-5.4.39/ext/json/json.c:642 #12 0x00002b8e1d5e275d in json_encode_array (buf=0x7fff42111ca0, val=0x7fff42111ba0, options=0) at /root/php-5.4.39/ext/json/json.c:304 #13 0x00002b8e1d5e8594 in php_json_encode (buf=0x7fff42111ca0, val=0x2b8e1f493ed8, options=0) at /root/php-5.4.39/ext/json/json.c:642 #14 0x00002b8e1d5e8d15 in zif_json_encode (ht=1, return_value=0x2b8e1f492978, return_value_ptr=0x0, this_ptr=0x0, return_value_used=1) at /root/php-5.4.39/ext/json/json.c:778 ... --------------------------------------------- json_encode() called so many mmap() syscalls and didn't call any munmap() syscalls. Is this a memory leak of json_encode()? Or any other purpose like memory reuse? Test script: --------------- <?php // some large data from remote server consisting of utf8 unicde char. // (It's a just example.) $text = str_repeat("abcdefg123456한글입니다", 100); $data = "{\"result\":[" . str_repeat("{\"" . $text . "\":\"" . $text . "\"},", 1000); $data = rtrim($data, ","); $data .= "]}"; // make a json object $json = json_decode($data); // manipulating the json object // return a result echo json_encode($json); ?> -- Edit bug report at https://bugs.php.net/bug.php?id=69305&edit=1 -- Try a snapshot (PHP 5.4): https://bugs.php.net/fix.php?id=69305&r=trysnapshot54 Try a snapshot (PHP 5.5): https://bugs.php.net/fix.php?id=69305&r=trysnapshot55 Try a snapshot (trunk): https://bugs.php.net/fix.php?id=69305&r=trysnapshottrunk Fixed in SVN: https://bugs.php.net/fix.php?id=69305&r=fixed Fixed in release: https://bugs.php.net/fix.php?id=69305&r=alreadyfixed Need backtrace: https://bugs.php.net/fix.php?id=69305&r=needtrace Need Reproduce Script: https://bugs.php.net/fix.php?id=69305&r=needscript Try newer version: https://bugs.php.net/fix.php?id=69305&r=oldversion Not developer issue: https://bugs.php.net/fix.php?id=69305&r=support Expected behavior: https://bugs.php.net/fix.php?id=69305&r=notwrong Not enough info: https://bugs.php.net/fix.php?id=69305&r=notenoughinfo Submitted twice: https://bugs.php.net/fix.php?id=69305&r=submittedtwice register_globals: https://bugs.php.net/fix.php?id=69305&r=globals PHP 4 support discontinued: https://bugs.php.net/fix.php?id=69305&r=php4 Daylight Savings: https://bugs.php.net/fix.php?id=69305&r=dst IIS Stability: https://bugs.php.net/fix.php?id=69305&r=isapi Install GNU Sed: https://bugs.php.net/fix.php?id=69305&r=gnused Floating point limitations: https://bugs.php.net/fix.php?id=69305&r=float No Zend Extensions: https://bugs.php.net/fix.php?id=69305&r=nozend MySQL Configuration Error: https://bugs.php.net/fix.php?id=69305&r=mysqlcfg

« previous php.bugs (#191614) next »