php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78076 Opcache greatly increases memory usage.
Submitted: 2019-05-27 21:25 UTC Modified: 2022-12-01 16:34 UTC
Votes:5
Avg. Score:5.0 ± 0.0
Reproduced:4 of 4 (100.0%)
Same Version:3 (75.0%)
Same OS:1 (25.0%)
From: tyler dot bannister at remote-learner dot net Assigned: dmitry (profile)
Status: Duplicate Package: opcache
PHP Version: 7.2.18 OS: Centos 7.4.1708
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: tyler dot bannister at remote-learner dot net
New email:
PHP Version: OS:

 

 [2019-05-27 21:25 UTC] tyler dot bannister at remote-learner dot net
Description:
------------
Using the database install script for Moodle 3.2, 3.3, 3.4, 3.5 or Totara 10, 11 or 12 with PHP 7.1.28 or 7.1.29 when opcache is turned on the script runs out of memory even if the memory limit is increased to 2 GB, when opcache is turned off the script uses 78 MB of memory, when opcache is turned on it ran out of memory with 2 GB of memory allowed, at 4 GB of memory the script was killed before it could complete but it looked like it was using all of that memory before it was killed.

I suspect that issue is that during installation the Moodle install script does something incredibly stupid, it turns off caching of language strings (it's multi-language system) which means every time it needs to print a message it includes the file that contains the string.  Over the course of the database install it ends up including each file hundreds of times and with or without opcache enabled each of those includes seems to increase the amount of memory used, but with opcache enabled the memory usage grows much faster.

I've written a pair of simple test scripts to illustrate this behaviour.

Test script:
---------------
test1.php:
<?php
print("Starting Memory:". memory_get_usage() ."\n");
for ($x = 1; $x < 10000; $x += 1) {
    include("test2.php");
}
print("Ending Memory:". memory_get_usage() ."\n");

test2.php:
<?php
$a = "Hello World!\n";


Expected result:
----------------
When test1.php and test2.php are placed in the same directory and the scrits are run with opcache enabled and opcache disabled they should produce roughly the same starting and ending memory sizes.


Actual result:
--------------
Opcache disabled:
Starting Memory:349712
Ending Memory:349872

Opcache enabled:
Starting Memory:348856
Ending Memory:7820120


Patches

Pull Requests

Pull requests:

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-05-28 10:24 UTC] cmb@php.net
-Status: Open +Status: Feedback -Assigned To: +Assigned To: cmb
 [2019-05-28 10:24 UTC] cmb@php.net
PHP 7.1 receives only security fixes.  Can you reproduce the issue
with any of the actively supported PHP versions[1].

[1] <https://www.php.net/supported-versions.php>
 [2019-05-28 15:09 UTC] tyler dot bannister at remote-learner dot net
I was able to confirm the problem also exists in PHP 7.2.18.
 [2019-05-28 15:13 UTC] cmb@php.net
-Status: Feedback +Status: Open -PHP Version: 7.1.29 +PHP Version: 7.2.18 -Assigned To: cmb +Assigned To:
 [2019-05-28 15:13 UTC] cmb@php.net
Thanks!
 [2019-05-28 15:43 UTC] tyler dot bannister at remote-learner dot net
PHP 7.28 actual output:
Opcache enabled:
Starting Memory:385248
Ending Memory:7856480

Opcache disabled:
Starting Memory:386104
Ending Memory:386232

PHP 7.3.5 actual output:
Opcache enabled:
Starting Memory:389112
Ending Memory:8450224

Opcache disabled:
Starting Memory:389904
Ending Memory:390088
 [2019-05-28 16:06 UTC] tyler dot bannister at remote-learner dot net
I've continued testing the problem, and on the command line I was able to stop the memory explosion in my test script by setting opcache.file_cache_only=0.

However, I only enabled that setting in the first place to deal with the problem of running out of memory with the Moodle installer.  So the issue isn't exclusive to having file_cache_only enabled, but maybe that setting makes the problem worse?

The minimal number of non-default settings to replicate (on my now Centos 7.6.1810 with PHP 7.3.5 system) seems to be:
opcache.enable=1
opcache.enable_cli=1
opcache.file_cache="/var/lib/php/cli-opcache"
opcache.file_cache_only=1

I was also able to replicate the problem on Ubuntu 18.04.2 with PHP 7.2.17:
Opcache enabled with opcache.file_cache_only enabled:
Starting Memory:389008
Ending Memory:7860232

Opcache enabled with opcache.file_cache_only disabled:
Starting Memory:388432
Ending Memory:388432

Opcache disabled:
Starting Memory:389992
Ending Memory:390144
 [2020-02-18 14:58 UTC] cmb@php.net
-Status: Open +Status: Verified
 [2020-02-18 14:58 UTC] cmb@php.net
I can confirm the reported behavior (PHP 7.3 and 7.4 on Windows 10).
 [2020-03-29 22:18 UTC] thedinosaurmail at gmail dot com
The following pull request has been associated:

Patch Name: fix bug 78076
On GitHub:  https://github.com/php/php-src/pull/5321
Patch:      https://github.com/php/php-src/pull/5321.patch
 [2020-03-31 07:14 UTC] dmitry@php.net
-Assigned To: +Assigned To: dmitry
 [2020-03-31 08:22 UTC] dmitry@php.net
Unfortunately the fix proposed at https://github.com/php/php-src/pull/5321 is incorrect. It causes use-after-free and following crash.

Opcache in file_cache_only mode uses CG(arena) to store data loaded from file cache by the end of request. This is done by design, because all the functions and classes loaded from file cache are kept by the end of request anyway. The only part that is not necessary after the include() finishes - main op_array. In general, it should be possible to detect if file_cache contains only main op_array, then copy all relevant parts to emalloc()-ed process memory and then deallocate buffer. However, this is not an easy fix.
 [2021-04-25 02:25 UTC] turchanov at farpost dot com
Are there any plans to fix this?

This bug effectively prevents us from using OPCache in "cli" mode. Using file_cache_only=1 seems very logical/practical for cli mode. And we hit memory_limit due to this bug.

An alternative - 'file_cache_only=0', means that every running cli php will have its own private SHM cache of 200M (yes, we cache a lot!). This incurs a HUGE memory waste.
 [2022-12-01 16:34 UTC] cmb@php.net
-Status: Verified +Status: Duplicate
 [2022-12-01 16:34 UTC] cmb@php.net
Closing as duplicate of <https://github.com/php/php-src/issues/9812>.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Oct 31 23:01:28 2024 UTC