Make WordPress Core

Opened 2 years ago

Last modified 11 months ago

#56390 new enhancement

Updating WP_MEMORY_LIMIT

Reported by: javiercasares's profile JavierCasares Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: Bootstrap/Load Keywords:
Focuses: performance Cc:

Description

During the Contributor Day at the WordCamp Europe 2022, the Hosting Team found that WP_MEMORY_LIMIT is set as 40 MB (single site) and 64 MB (multisite). Furthermore, the WP_MAX_MEMORY_LIMIT is set as 256 MB.

WP_MEMORY_LIMIT is the value for the WordPress Memory Limit, usually referred to the frontend memory, and WP_MAX_MEMORY_LIMIT is the value for the PHP Memory Limit, usually referred to the backend memory.

History

Around September 2013, the WP_MEMORY_LIMIT value changed from 32 MB to 40 MB (32+8). Some tests done by the Hosting Team suggest that the memory used on WordPress is around 16 MB.

The PHP memory_limit sets the maximum amount of memory in bytes that a script is allowed to allocate. This helps prevent poorly written scripts for eating up all available memory on a server. Note that to have no memory limit, set this directive to -1. Check the PHP page for more information.

Actual code

Checking the default-constants.php, the code for WP_MEMORY_LIMIT is:

$current_limit = ini_get( 'memory_limit' );
$current_limit_int = wp_convert_hr_to_bytes( $current_limit );

// Define memory limits.
if ( ! defined( 'WP_MEMORY_LIMIT' ) ) {
  if ( false === wp_is_ini_value_changeable( 'memory_limit' ) ) {
    define( 'WP_MEMORY_LIMIT', $current_limit );
  } elseif ( is_multisite() ) {
    define( 'WP_MEMORY_LIMIT', '64M' );
  } else {
    define( 'WP_MEMORY_LIMIT', '40M' );
  }
}

// Set memory limits.
$wp_limit_int = wp_convert_hr_to_bytes( WP_MEMORY_LIMIT );
if ( -1 !== $current_limit_int && ( -1 === $wp_limit_int || $wp_limit_int > $current_limit_int ) ) {
  ini_set( 'memory_limit', WP_MEMORY_LIMIT );
}

NOTE: this code is an extrapolation of some parts to understand the values.

For WP_MAX_MEMORY_LIMIT, is:

$current_limit = ini_get( 'memory_limit' );
$current_limit_int = wp_convert_hr_to_bytes( $current_limit );

if ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) ) {
  if ( false === wp_is_ini_value_changeable( 'memory_limit' ) ) {
    define( 'WP_MAX_MEMORY_LIMIT', $current_limit );
  } elseif ( -1 === $current_limit_int || $current_limit_int > 268435456 /* = 256M */ ) {
    define( 'WP_MAX_MEMORY_LIMIT', $current_limit );
  } else {
    define( 'WP_MAX_MEMORY_LIMIT', '256M' );
  }
}

NOTE: this code is an extrapolation of some parts to understand the values.

PHP values

The first part gets the value from PHP, and if not exists, sets a default value. Thereafter, if the value is incorrect (in bytes) sets the memory limit from the constant.

This PHP value has evolved:

Some questions

Why change the WP_MEMORY_LIMIT value?

To level it to the PHP standard.

If the hoster has some kind of limitation, misconfiguration, an incorrect value or does not allow changing it, the value used is the lesser, of 40 MB, which usually produces memory errors, when it should use the PHP default value, which is generally acceptable in new installations. At this time, 20 latest versions of WordPress (since WordPress 4.1 / 2014-12-17) can use PHP 5.6.40+ so it would meet the minimums set by PHP.

Can, actually, the value be greater than the PHP value?

Yes. That's why there is an intent to include something like:

WP_MEMORY_LIMIT <= WP_MAX_MEMORY_LIMIT <= memory_limit

Premises

We should keep in mind some basic assumptions when incorporating PHP memory limits based on what users can do.

The memory limit set by computer systems are set for a reason. And that reason should be enforced; therefore, PHP's memory limit should not be exceeded, and in case it needs to be exceeded, it should be changed by the system administration.

Users can set the values they want from the wp-config.php configuration file. Often, extremely high values are set to hide a memory consumption problem due to bad programming. With a few visits it usually works, but it is a short-term fix.

We must be realistic about the memory limits of the WordPress Core and the normal use of a WordPress, whether it is a simple WordPress or a WordPress Multisite. Most WordPress sites install plugins and themes that make memory spikes higher.

PHP has its baseline memory limits that should serve as a reference for its use and application.

Proposal

Considering that since 2008, and PHP >5.2.0 the memory_limit value is equal to 128 MB, should we consider an update of this value in the WordPress base configuration, or at least an update of the values?

The proposal from the WordPress Hosting team is for WP_MEMORY_LIMIT:

  • WordPress Single: define('WP_MEMORY_LIMIT', '128M');
  • WordPress Multisite: define('WP_MEMORY_LIMIT', '192M');

Another patch should be:

WP_MEMORY_LIMIT <= WP_MAX_MEMORY_LIMIT <= memory_limit

Users can modify the WP_MEMORY_LIMIT and WP_MAX_MEMORY_LIMIT at wp-config.php and should have some limitations in values, as far as WordPress cannot overflow PHP.

Getting the values

When doing some calls to PHP functions and values, got this:

  • php.ini: memory_limit -> value: 256M
  • function: memory_get_usage -> value: 2097152
  • updating the ini_set memory_limit to 512M -> value: memory_limit = 256M
  • function: ini_get_all[memory_limit]
    Array (
      [global_value] => 256M
      [local_value] => 512M
      [access] => 7
    )
    

So, the real values are, always in the ini_get_all[memory_limit].

After doing some tests, maybe hard-coding the values is a bad idea, but having some "limits" is cool (like now) but reading the real values.

New code

This is just a proposal of code (need revision and checking by the WordPress Core Team).

$default_max_memory = 128 * MB_IN_BYTES; // this is a security limit. Should be align with the default PHP memory_limit. Now (PHP 5.3+) is 128M

$memory_default = ini_get( 'memory_limit' );

$ini_get_all = ini_get_all();

// set by global ini
if( isset( $ini_get_all['memory_limit']['global_value'] ) ) {
  $max_memory_default = $ini_get_all['memory_limit']['global_value'];
} elseif( $memory_default ) {
  $max_memory_default = $memory_default;
} else {
  $max_memory_default = $default_max_memory;
}

// set by site / virtualhost / pool ini
if( isset( $ini_get_all['memory_limit']['local_value'] ) ) {
  $max_memory_real = $ini_get_all['memory_limit']['local_value'];
} else {
  $max_memory_real = $max_memory_default;
}
unset( $memory_default, $ini_get_all );

// default memory in bytes
$max_memory_default_int = wp_convert_hr_to_bytes( $max_memory_default );
if( $max_memory_default_int <= 0 ) $max_memory_default_int = $default_max_memory;

// site memory in bytes
$max_memory_real_int = wp_convert_hr_to_bytes( $max_memory_real );

if( $max_memory_real_int <= 0 ) $max_memory_real_int = $default_max_memory;

if( $max_memory_real_int < $max_memory_default_int ) $max_memory_real_int = $max_memory_default_int; // set the limit to the max memory set wherever

// user did not set the WP_MEMORY_LIMIT in wp-config.php
if ( ! defined( 'WP_MEMORY_LIMIT' ) ) {
  define( 'WP_MEMORY_LIMIT', size_format( $max_memory_real_int ) );
// if the WP_MEMORY_LIMIT set by the user is greater than the real available
} elseif( $max_memory_real_int < wp_convert_hr_to_bytes( WP_MEMORY_LIMIT ) ) {
  define( 'WP_MEMORY_LIMIT', size_format( $max_memory_real_int ) );
}

// user did not set the WP_MAX_MEMORY_LIMIT in wp-config.php
if ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) ) {
  define( 'WP_MAX_MEMORY_LIMIT', size_format( $max_memory_real_int ) );
// if the WP_MAX_MEMORY_LIMIT set by the user is greater than the real available
} elseif( $max_memory_real_int < wp_convert_hr_to_bytes( WP_MAX_MEMORY_LIMIT ) ) {
  define( 'WP_MAX_MEMORY_LIMIT', size_format( $max_memory_real_int ) );
}
if ( wp_convert_hr_to_bytes( WP_MEMORY_LIMIT ) > wp_convert_hr_to_bytes( WP_MAX_MEMORY_LIMIT ) ) {
  WP_MEMORY_LIMIT = WP_MAX_MEMORY_LIMIT;
}
unset( $default_max_memory, $max_memory_default, $max_memory_real, $max_memory_default_int, $max_memory_real_int );

Initial Props: @javiercasares, @crixu, @bernardzijlstra, @mikeschroder.

Original document from the Hosting team at
https://docs.google.com/document/d/1CFMboqFnHMBifcuozqWKvUQUdxSCqCh-YcCwMOMeAl0/

Change History (33)

This ticket was mentioned in Slack in #hosting-community by javier. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by javier. View the logs.


2 years ago

#3 follow-up: @desrosj
2 years ago

  • Focuses performance added

I haven't yet had a chance to fully think this through and do any testing, but I wanted to point out that the discussion around this would benefit from a proposal being published on the Making WordPress Core blog.

While it's Hosting team specific, the Core blog casts a wider net for feedback, and it is a change specific to WordPress Core so still fits.

Also, I was curious if the Hosting team had synced up with the Performance team on this one. Increasing the default memory limit will impact performance, so the contributors focusing on that area of WordPress may also be interested in helping out. After the proposal is published, it can be cross posted to the performance team blog.

#4 in reply to: ↑ 3 ; follow-up: @JavierCasares
2 years ago

Replying to desrosj:

I can create a post in the Hosting P2, pointing to this ticket and x-post with Core and Performance.

I know the Performance Team knows about this because we talked in the WCEU22 Contributor Day and also some of the Team are in the Hosting chat.

Also, about Core, I sent the proposal two weeks ago to Core-PHP and Core. They told me they will talk about, but, not a lot more, so, here we are :)

There is no rush in this ticket, so we can work it a little more with all the teams :)

This ticket was mentioned in Slack in #hosting-community by jadonn. View the logs.


2 years ago

#6 in reply to: ↑ 4 @JavierCasares
2 years ago

Replying to JavierCasares:

I can create a post in the Hosting P2, pointing to this ticket and x-post with Core and Performance.

https://make.wordpress.org/hosting/2022/08/18/proposal-updating-wp_memory_limit/

#7 follow-ups: @dd32
2 years ago

Why change the WP_MEMORY_LIMIT value?

To level it to the PHP standard.

If the hoster has some kind of limitation, misconfiguration, an incorrect value or does not allow changing it, the value used is the lesser, of 40 MB, which usually produces memory errors, when it should use the PHP default value [...]

If I'm understanding this correctly, the real concern here is not that the value of 40/64M is too low for WordPress, but rather, that under certain systems WordPress may accidentally lower the memory limit from something much higher to 40M, correct?

If that's the case, this seems to be going about it the wrong way, instead of changing where the limit comes from, if we can't detect a valid value (ie. maybe it's 0?) it should just leave the memory as-is and not change anything?

Based on previous tickets (see below), it seems to me that using ini_get_all()['memory_limit']['global_value'] is mostly irrelevant. Just because global_value is 1G, doesn't mean we should use that as our default.

As far as I can tell though, this statement should be truthful:

ini_get( 'memory_limit' ) === ( ini_get_all()['memory_limit']['local_value'] ?: ini_get_all()['memory_limit']['global_value'] )

Previously, Duplicate Of, See also, etc: #29341, #52143, #51153, #37680

https://core.trac.wordpress.org/ticket/52143#comment:3 is interesting though, it sounds like ini_get( 'memory_limit' ) doesn't work on their hosting properly, and instead of fixing that they simply make WP_MEMORY_LIMIT set to the same invalid value so core doesn't do anything with it.

memory_get_usage()

I'm not sure why that function is even mentioned, that's unrelated to memory limits, but rather, it's the amount of memory currently allocated to the process (Maximum memory is not allocated to the process unless it's using all it's memory limits).

#8 in reply to: ↑ 7 @dd32
2 years ago

Replying to dd32:

If the hoster has some kind of limitation, misconfiguration, an incorrect value or does not allow changing it, the value used is the lesser, of 40 MB, which usually produces memory errors, when it should use the PHP default value [...]

If I'm understanding this correctly, the real concern here is not that the value of 40/64M is too low for WordPress, but rather, that under certain systems WordPress may accidentally lower the memory limit from something much higher to 40M, correct?

To add more clarity to that - I guess my point is, that it doesn't need to match the PHP default values, rather, it should inherit whatever the system has allocated but increase it to 40/64M if the value is absolutely set lower. It's not the default memory limit, it's the absolute minimum memory limit WordPress wants.

#9 in reply to: ↑ 7 ; follow-up: @JanR
2 years ago

Replying to dd32:

Replying to JavierCasares:

During the Contributor Day at the WordCamp Europe 2022, the Hosting Team found that WP_MEMORY_LIMIT is set as 40 MB (single site) and 64 MB (multisite). Furthermore, the WP_MAX_MEMORY_LIMIT is set as 256 MB.

I hope this is not new information for the Hosting Team, these memory limits are known, documented and in-place for years. However, this is not really always the case. Read on.

Why change the WP_MEMORY_LIMIT value?

[...]

If the hoster has some kind of limitation, misconfiguration, an incorrect value or does not allow changing it, the value used is the lesser, of 40 MB, which usually produces memory errors, when it should use the PHP default value [...]

If I'm understanding this correctly, the real concern here is not that the value of 40/64M is too low for WordPress, but rather, that under certain systems WordPress may accidentally lower the memory limit from something much higher to 40M, correct?

That is correct. Or at least, in some circumstances. I've seen a lot of plugins and themes doing it wrong in the past.

But look at the code (bear with my, I hope I read it correctly) and imagine PHP's memory_limit is set to 134 MB.

https://github.com/WordPress/WordPress/blob/master/wp-includes/default-constants.php#L46
https://github.com/WordPress/WordPress/blob/master/wp-includes/default-constants.php#L68

Here

ini_set( 'memory_limit', WP_MEMORY_LIMIT );

is only called if $wp_limit_int > $current_limit_int (I can't imagine situations when there is no current limit set in php.ini, other than some development environments perhaps). So nothing changes if the current PHP limit is higher than the new limit.

However, remember that PHP memory_limit can/may be changed anywhere, so wp_is_ini_value_changeable( 'memory_limit' ) returns always true. This makes this check obsolete in my opinion.

For reference:

$ grep -i _limit wp-includes/default-constants.php
        $current_limit     = ini_get( 'memory_limit' );
        $current_limit_int = wp_convert_hr_to_bytes( $current_limit );
        if ( ! defined( 'WP_MEMORY_LIMIT' ) ) {
                if ( false === wp_is_ini_value_changeable( 'memory_limit' ) ) {
                        define( 'WP_MEMORY_LIMIT', $current_limit );
                        define( 'WP_MEMORY_LIMIT', '64M' );
                        define( 'WP_MEMORY_LIMIT', '40M' );
        if ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) ) {
                if ( false === wp_is_ini_value_changeable( 'memory_limit' ) ) {
                        define( 'WP_MAX_MEMORY_LIMIT', $current_limit );
                } elseif ( -1 === $current_limit_int || $current_limit_int > 268435456 /* = 256M */ ) {
                        define( 'WP_MAX_MEMORY_LIMIT', $current_limit );
                        define( 'WP_MAX_MEMORY_LIMIT', '256M' );
        $wp_limit_int = wp_convert_hr_to_bytes( WP_MEMORY_LIMIT );
        if ( -1 !== $current_limit_int && ( -1 === $wp_limit_int || $wp_limit_int > $current_limit_int ) ) {
                ini_set( 'memory_limit', WP_MEMORY_LIMIT );

One can argue hosting companies should (must) set reasonable limits, but don't forget they're set for a reason. In my opinion, PHP memory_limit should be at least > 128 MB, preferably 256 MB but plugins that require more must be killed :)

#10 in reply to: ↑ 9 ; follow-up: @dd32
2 years ago

Replying to JanR:

That is correct. Or at least, in some circumstances. I've seen a lot of plugins and themes doing it wrong in the past.

The notion behind that post is exactly why I commented, this statement seems to be untrue to me:

in a situation where PHP memory_limit is set higher than a custom WP_MEMORY_LIMIT in wp-config.php, this may causes problems. You are basically decreasing the amount of memory available to WordPress through WP_MEMORY_LIMIT and WP_MAX_MEMORY_LIMIT.

This quote is also totally wrong/not-required; Unless you're running a buggy theme/plugin that doesn't check correctly.. and even then.. this line you pointed out takes care of that anyway..

After increasing PHP’s memory limit, you can now create a WP_MEMORY_LIMIT constant in your wp-config file. Use the following syntax to set it to your currently configured PHP limit.

lot of plugins and themes "doing it wrong"

The example of the Jupiter theme there is a good example of a buggy theme, I don't think confusion from a theme author is reason to change this in WordPress though.

The example of WPML seems unwarranted, they're listing both the php.ini value and the constant value, It's not clear how it's being used, but it looks like it's part of debugging information based on the contents of the array, in which case seems fine..

However, remember that PHP memory_limit can/may be changed anywhere, so wp_is_ini_value_changeable( 'memory_limit' ) returns always true. This makes this check obsolete in my opinion.

I would agree, that check seems obsolete at first, however, I believe using tools such as suhosin can disable the ability to modify some ini settings such as this. However, even being able to set it doesn't mean that such tools won't have prevented it (ie. Request 10G and it says "Nope, you get 2G max"). It's also possible to set the PHP memory limits higher than the system can provide, that's also not exactly WordPress' problem.

One can argue hosting companies should (must) set reasonable limits, but don't forget they're set for a reason. In my opinion, PHP memory_limit should be at least > 128 MB, preferably 256 MB but plugins that require more must be killed :)

And that's the crux of this - Hosting companies should set reasonable limits, but all of this code in WordPress related to memory is specifically for hosts who do not, it's not at all about overriding what a host has done, it's about making WordPress work on a host who has re-used a php.ini from 2005 in 2022 with an abysmal memory_limit value.

Last edited 2 years ago by dd32 (previous) (diff)

#11 in reply to: ↑ 10 @JanR
2 years ago

Off topic reply:

Replying to dd32:

Replying to JanR:

That is correct. Or at least, in some circumstances. I've seen a lot of plugins and themes doing it wrong in the past.

The notion behind that post is exactly why I commented, this statement seems to be untrue to me

Yeah, I need to rewrite that post. I don't remember what WordPress and WPML version it's based, but the post is from 2018 and a lot has changed since then. The reason for it was in fact WPML's behavior we encountered in 2017.

This ticket was mentioned in Slack in #hosting-community by javier. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by jadonn. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by crixu. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by javier. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by javier. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by amykamala. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by javier. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by jadonn. View the logs.


2 years ago

#20 @jason_hayes
2 years ago

I definitely think it needs be higher. I would recommend 512MB or 1024MB. Todays servers come with 4GB or 8GB.

I set PHP to 2048M to run large WordPress sites and I'm using caching software, too. I didn't realize this limitation was built into WordPress until a support tech asked me to look at the WordPress Site Settings in Site Health for something unrelated. After updating 5 or 6 sites in the wp-config to 1024M, I thought I better look at the WordPress roadmap and see if and when 40M would be lifted.

#21 @JavierCasares
2 years ago

If hosters wants to increase the default value, it can be done via the wp-config.php file.

The idea behind this ticket is double:

  • Setting the default value as the PHP default value (as a minimum one)
  • Setting some control, so users cannot overflow the memory with inadequate values (over the hosting / PHP set)

#22 @sabernhardt
2 years ago

  • Component changed from General to Bootstrap/Load

This ticket was mentioned in Slack in #hosting-community by javier. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by chaion07. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by amykamala. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by javier. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by javier. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by jadonn. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by javier. View the logs.


2 years ago

This ticket was mentioned in Slack in #hosting-community by jessibelle. View the logs.


2 years ago

#31 @SergeyBiryukov
22 months ago

#57794 was marked as a duplicate.

This ticket was mentioned in Slack in #hosting by javier. View the logs.


11 months ago

This ticket was mentioned in Slack in #hosting by crixu. View the logs.


11 months ago

Note: See TracTickets for help on using tickets.