Since my question is getting longer and longer, I decide to re-write the whole question to make it better and shorter.
I run my website on dedicated server with 8GB memory. I am fully aware that I need to raise the memory limit on php.ini setting. I have set it from 128M to 256M and to -1. Still the problem is persistence.
Fatal error: Out of memory (allocated 786432) (tried to allocate 24576 bytes) in D:\www\football\views\main.php on line 81
The out of memory does not make sense because it said only 786432 bytes is allocated and it needed 24576 bytes more.
786432 bytes is only 768 kilobytes and is fairly small.
Hints
- The error occurs on a very random line. It does not always error on line number 81.
- At peak time, Apache only takes around 500mb of memory. I still have 6GB to spare.
- There is no infinite loop.
- The script takes 1,042,424 bytes. Getting this number from
echo memory_get_peak_usage();
- The resultset from MySQL is small (at most 12 of rows, purely text, no blob data)
- (Important) If I restart Apache once every two days, the error is gone. It usually happens when Apache is running more than 2 days.
- I have included the profiling the script and you can get it here.
- This dedicated server is purely used to run only one website. This website is a high traffic website with average of 1,000 visitors every minute. At peak time, there will be 1,700 to 2,000 visitors accessing at the same time.
Server Spec
OS: Windows 2008 R2 64-Bit
CPU: Intel Core i5 - 4 cores
RAM: 8 GB
Apache 2.2
PHP 5.3.1
Storage: 2 x 1 TB hard drives
Bandwidth: 10 TB per month
Solution
I have finally tuned up and fixed the problem and I would like to share it here what I have done to improve:
favicon.ico
was missing which mess up with my route engine. Although my route engine is very small, but by includingfavicon.ico
, it helps reduce memory usage by not running my route engine. Most of part of my website has it and I forgot to put it for this new section.Limit
MaxRequestPerChild
helps. In my other dedicated server, I have myMaxRequestPerChild
limited. For this server, I set it to 0. I always thought that each script is isolated. Lets say if my script takes 800kb to run. Upon its completion, Apache or PHP should free 800kb memory. It seem like it doesn't work this way. LimitedMaxRequestPerChild
does help to prevent memory leak by creating new process after limitedMaxRequestPerChild
and the old process is dying. This is my new setting.ThreadsPerChild 1500 MaxRequestsPerChild 10000
ob_flush();
does reduce slightly more memory. It does not help much but every bit of optimization helps.- I have used
xdebug
which I have never used before as suggested by people who attempt to answer this question. I have to say it is great tool and I have optimized a few stuffs to make it run slightly faster. - I have disable a few unnecessary Apache module. I am trying to disable it one by one and leave it a few days test to ensure it works perfectly before I disable another one. I do have all unnecessary PHP extension disable now.
- Most of my script in this server used traditional way (no template, no database layer, pure PHP, HTML, and legacy mysql_* function). To be honest, it runs very fast and used extremely small memory. However, maintenance the script is not very easy as the website is getting longer. I have tried to convert some parts of the website into proper framework (my own tiny framework). The reason that I used my own framework because it is tiny (3kb for the whole framework and include only what I need).
- Switching to IIS7.5 solving this problem completely.