Conditionally increase the PHP memory limit on Drupal

On any Drupal project, you may face this kind of log:

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 6369280 bytes) in ...

This happens when a PHP process is reaching its memory limit and cannot achieve the requested task. This type of error can happen for many reasons including image manipulation, faulty migration or erroneously designed code to name a few examples. Before updating the memory allocated to PHP, it is always better to investigate the process causing the issue. This is important since increasing the memory may be a temporary patch, whereas the root cause could be due to erroneous code design.

There are however some operations such as image manipulation and media uploads that require more memory for PHP processes. The most straightforward fix is to increase the memory limit allowed per PHP process. This is valid if your entire application consumes a lot of memory, and globally requires more bandwidth. But in most cases, these are very specific operations which are reaching capacity limitations. Increasing the memory globally is not a good idea as it means less PHP processes will be capable of being performed in parallel. In short, if PHP has access to 1Gb and is configured to grant 512Mb to each PHP process, that would mean your application can only serve 2 requests in parallel. Keeping the memory limit to 128Mb and conditionally increasing the limit to 512Mb for the few expensive processes is a much better use of the available memory.

Why a module ?

As detailed on this Acquia KB article, it is possible to override the memory limit by adding code in the settings.php file. The caveat however is it requires code change, which may not be an easy task, and it may also lead to more complex and difficult code to maintain. The purpose of the module is to avoid adding complexity to the code, making it easier to maintain and configure via UI.

Some common situations where memory limitations can be an issue include:

  • Sites/default/files/styles/* which will generate an image variation and can be a bottleneck in case the original image is too heavy.
  • Admin/structure/taxonomy/management/*/overview which is the page listing the terms of a vocabulary and can be an issue when there are too many terms.
  • The submit of media upload form.

What does the module offer?

The Memory Limit Policy module which can be used to configure policies to conditionally increase the memory limit.

This module comes with different plugins to alter the memory based on:

  • The path
  • The presence of a query argument
  • The user role
  • The route name
  • The HTTP method
  • The Drush command (please note that it comes with some limitation).

Plugins can be combined to be more restrictive on when to change memory limitations. They are designed to be easy to extend as policies are plugins which mean you can create your own policy if your conditions are very specific.

How to configure the module?

Say we want to increase the memory allocated to the process which generates image presets to 256Mb.

Once the module is enabled, policies are listed in Configuration > Performance > Memory Limit Policy > Policies (/admin/config/performance/memory-limit-policy/list).

Image
Memory limit policy - list policies

 

To create a new policy, click the “+ Add policy” button.

It displays the first step of the policy configuration. You must give a name to the policy (“Image style” in our example) and choose the memory that the policy will apply when the conditions are met (“256M” in our example). The format must respect the shorthand byte format. 100Kb for 100 kilobytes, 100Mb for 100 megabytes and 1Gb for 1 gigabytes. This is the same format which is used in php.ini to configure the global memory limit.

Image
Memory limit policy - create policy step 1

 

The second step of the policy setup is to configure the constraints which determine if the policy applies. Be sure to enable some Memory Limit Policy sub-modules which provide some constraint methods, or you can create your own. If you don’t configure any constraints, the policy will always apply. If that is really what you want, using a module will likely not be the best choice and updating the PHP configuration globally will probably be preferable.

Image
Memory limit policy - create policy step 2

 

Each constraint will come with its own configuration form. It is possible to negate the constraint. For example, if you need to increase the memory on all frontend pages but not on the admin ones, it can be achieved by using the “Path” constraint with “/admin/” and the negate option. In our example, we will use the “Path” constraint and enter “/sites/default/files/styles/” as the path.

Image
Memory limit policy - create policy step 3
Image
Memory limit policy - create policy step 3 bis

 

Finally, click the “Finish” button to get the constraints saved. The policy is now listed.

Image
Memory limit policy - list policies 2

 

All policies listed will be evaluated. In some situations, it may be needed to order the policies using drag & drop.

For some complex cases, it may be difficult to evaluate if a policy applies. To validate a policy is applied, we can use the settings to add the memory information in the headers. The settings can be set in Configuration > Performance > Memory Limit Policy > Configuration (/admin/config/performance/memory-limit-policy/settings).

If no policy applies, headers will only indicate the default memory limit.

Image
Memory limit policy - Headers

 

If a policy applies, headers will indicate the name of the policy and the new memory limit applied.

Image
Memory limit policy - Headers 2

 

Finally, export the configuration and push to your version control.

id: image_style
label: 'Image style'
weight: null
status: true
memory: 256M
langcode: en
policy_constraints:
  -
    id: path
    negate: false
    paths: '/sites/default/files/styles/*'
dependencies: {  }

The existing Memory Limit Policy sub-modules already cover a large variety of situation and fine-tuning the memory limit to fit each situation should not be an issue with the module. A future article will describe how to create a custom plugin to override the memory limit in a very specific case.