Make WordPress Core

Changeset 60435


Ignore:
Timestamp:
07/08/2025 09:00:01 AM (6 months ago)
Author:
audrasjb
Message:

Editor: Free up transient memory leak in do_blocks().

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.

This commit also includes follow-up changes committed in [60400] and [60402].

Rewieved by audrasjb.
Merges [60316], [60400] and [60402] to the 6.8 branch.
Props dmsnell, joemcgill.
Fixes #63588.

Location:
branches/6.8
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/6.8

  • branches/6.8/src/wp-includes/blocks.php

    r60434 r60435  
    24052405 */
    24062406function do_blocks( $content ) {
    2407     $blocks = parse_blocks( $content );
    2408     $output = '';
    2409 
    2410     foreach ( $blocks as $block ) {
    2411         $output .= render_block( $block );
     2407    $blocks                = parse_blocks( $content );
     2408    $top_level_block_count = count( $blocks );
     2409    $output                = '';
     2410
     2411    /**
     2412     * Parsed blocks consist of a list of top-level blocks. Those top-level
     2413     * blocks may themselves contain nested inner blocks. However, every
     2414     * top-level block is rendered independently, meaning there are no data
     2415     * dependencies between them.
     2416     *
     2417     * Ideally, therefore, the parser would only need to parse one complete
     2418     * top-level block at a time, render it, and move on. Unfortunately, this
     2419     * is not possible with {@see \parse_blocks()} because it must parse the
     2420     * entire given document at once.
     2421     *
     2422     * While the current implementation prevents this optimization, it’s still
     2423     * possible to reduce the peak memory use when calls to `render_block()`
     2424     * on those top-level blocks are memory-heavy (which many of them are).
     2425     * By setting each parsed block to `NULL` after rendering it, any memory
     2426     * allocated during the render will be freed and reused for the next block.
     2427     * Before making this change, that memory was retained and would lead to
     2428     * out-of-memory crashes for certain posts that now run with this change.
     2429     */
     2430    for ( $i = 0; $i < $top_level_block_count; $i++ ) {
     2431        $output      .= render_block( $blocks[ $i ] );
     2432        $blocks[ $i ] = null;
    24122433    }
    24132434
Note: See TracChangeset for help on using the changeset viewer.