Make WordPress Core

Changeset 60316


Ignore:
Timestamp:
06/18/2025 12:49:51 AM (7 months ago)
Author:
dmsnell
Message:

do_blocks(): Free up transient memory leak

There has been a memory inefficiency inside of do_blocks() where it
parses the given content then iterates through each top-level block to
render it. Unfortunately each top-level block can considerably add to
the overall memory use involved, and once moving on to the next
top-level block, all of the allocated memory will be retained until the
end of the call to do_blocks().

In this change, each parsed block sub-tree is freed via reset to null
after it has been rendered. All top-level blocks are rendered
independently of each other and so this operation is safe — there are no
data dependencies between them.

For a test post of length 2.3 MB containing 138 top-level blocks, this
brought the minimum memory requirement for the PHP process down from
around 450 MB to around 316 MB. This was “around” since the memory
requirements are non-deterministic and some runs will succeed while
other runs will crash for out-of-memory given the same memory_limit.

Impact of this change will be most profound when there exist one or
more top-level blocks which allocate a significant amount of memory
which are not the last top-level-block in a post. This means that
this change might even impact small and typical posts, if the right
blocks are near the start of the post.

Developed in https://github.com/wordpress/wordpress-develop/pull/8999
Discussed in https://core.trac.wordpress.org/ticket/63588

Props dmsnell, joemcgill.
Fixes #63588.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/blocks.php

    r60173 r60316  
    24042404 */
    24052405function do_blocks( $content ) {
    2406     $blocks = parse_blocks( $content );
    2407     $output = '';
    2408 
    2409     foreach ( $blocks as $block ) {
    2410         $output .= render_block( $block );
     2406    $blocks                = parse_blocks( $content );
     2407    $top_level_block_count = count( $blocks );
     2408    $output                = '';
     2409
     2410    for ( $i = 0; $i < $top_level_block_count; $i++ ) {
     2411        $output .= render_block( $blocks[ $i ] );
     2412        $blocks[ $i ] = null;
    24112413    }
    24122414
Note: See TracChangeset for help on using the changeset viewer.