|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2006-06-27 14:44 UTC] joe at estara dot com
Description:
------------
If you use unserialize on a large multidimensional array, each apache process it runs in ends up taking up over 68m of ram (the actual size depends on your array that you're unserializing) This is actual ram (Resident minus shared ram), and doesn't return it to the operating system after the script exits. Since you have say MaxClients in apache2 of 150, 150 times 68m of ram means swapping to death. This is using prefork.
Reproduce code:
---------------
<?php
ini_set("memory_limit", "64M");
# ziplatlong is an array, with zip code as a key and a 2 element lat long array as the value
$s = file_get_contents("ziplatlong");
$zip = unserialize($s);
preg_match("/foo/", $zip["00601"][0]);
Expected result:
----------------
I'd expect most of the ram returned to the operating system. When I do something similar, use the same levels of ram, apache only takes up ~10M of ram, even though it uses ~64M while processing.
<?php
ini_set("memory_limit", "64M");
for($i=0;$i<50; $i++)
$s[$i] = file_get_contents("ziplatlong");
preg_match("/foo/", $s[38]);
Actual result:
--------------
Machine swaps to death.
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Wed Nov 05 08:00:02 2025 UTC |
This is not the operating systems fault. This is PHP's fault. It's present in 4.4.0-4 as well. Under debian and fedora core 4. This leaks 800M of ram on a single run. <?php ini_set("memory_limit", "800M"); for($i=0;$i<160; $i++) $s[$i] = file_get_contents("ziplatlong"); for($i=0;$i<160; $i++) preg_match("/foo/", $s[$i]); This uses 800m but immediately returns it to the operating system under both versions and OSs. <?php ini_set("memory_limit", "800M"); for($i=0;$i<260; $i++) $s[$i] = file_get_contents("ziplatlong"); for($i=0;$i<260; $i++) preg_match("/foo/", $s[$i]); I'll email you a zip file so you can easily reproduce this PHP bug.It's 8 lines without comments. You want me to write a script to make the data file instead of just downloading it? <?php ini_set("memory_limit", "64M"); $s = file_get_contents("ziplatlong"); $z = unserialize($s); for($i=0;$i<10;$i++) $zip[$i] = unserialize($s); for($i=0;$i<10;$i++) preg_match("/asdfl/", $zip[$i]["00601"][0]); ?>Here, fully contained version that will make a 131M leak in 12 lines. <?php ini_set("memory_limit", "64M"); function make_arr() { for($i=0; $i<396768; $i++) $a[sprintf("%05d",$i)] = array(0 => "PHPLEAKS923889239823", 1 => "PHPLEAK2349082349898"); return $a; } for($i=0;$i<10;$i++) $zip[$i] = make_arr(); for($i=0;$i<10;$i++) preg_match("/asdfl/", $zip[$i]["00601"][0]); ?>Mike: Please just run this below script on your machine, and then use top, hit 'M' to sort by memory and apache will be the top memory user. hit the script 10 times and your machine will start swapping to death. This appears to be apache related: if the same script is hit, it doesn't leak MORE memory, it stays at the outrageously high level it got to the first time. <?php ini_set("memory_limit", "64M"); function make_arr() { for($i=0; $i<396768; $i++) $a[sprintf("%05d",$i)] = array(0 => "PHPLEAKS923889239823", 1 => "PHPLEAK2349082349898"); return $a; } for($i=0;$i<10;$i++) $zip[$i] = make_arr(); for($i=0;$i<10;$i++) preg_match("/asdfl/", $zip[$i]["00601"][0]); ?>Fixed in 5.2.0-Dev (though half the time it asks me if I want to download a blank file which I guess is different bug when it's near the memory limit?) It allocates more memory in this version but returns it all to the OS immediately on exit: <?php ini_set("memory_limit", "384M"); function make_arr() { for($i=0; $i<39678; $i++) $a[sprintf("%05d",$i)] = array(0=> "PHPLEAKS923889239823", 1 => "PHPLEAK2349082349898"); return $a; } for($i=0;$i<15;$i++) $zip[$i] = make_arr(); for($i=0;$i<15;$i++) preg_match("/asdfl/", $zip[$i]["00601"][0]); echo 'Script Ran<br/><br/>'; ?>