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.


Built from https://develop.svn.wordpress.org/branches/6.8@60435


git-svn-id: http://core.svn.wordpress.org/branches/6.8@59771 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
audrasjb
2025-07-08 09:01:25 +00:00
parent 48dd13b657
commit deec6283f4
2 changed files with 26 additions and 5 deletions

View File

@@ -2404,11 +2404,32 @@ function parse_blocks( $content ) {
* @return string Updated post content.
*/
function do_blocks( $content ) {
$blocks = parse_blocks( $content );
$output = '';
$blocks = parse_blocks( $content );
$top_level_block_count = count( $blocks );
$output = '';
foreach ( $blocks as $block ) {
$output .= render_block( $block );
/**
* Parsed blocks consist of a list of top-level blocks. Those top-level
* blocks may themselves contain nested inner blocks. However, every
* top-level block is rendered independently, meaning there are no data
* dependencies between them.
*
* Ideally, therefore, the parser would only need to parse one complete
* top-level block at a time, render it, and move on. Unfortunately, this
* is not possible with {@see \parse_blocks()} because it must parse the
* entire given document at once.
*
* While the current implementation prevents this optimization, its still
* possible to reduce the peak memory use when calls to `render_block()`
* on those top-level blocks are memory-heavy (which many of them are).
* By setting each parsed block to `NULL` after rendering it, any memory
* allocated during the render will be freed and reused for the next block.
* Before making this change, that memory was retained and would lead to
* out-of-memory crashes for certain posts that now run with this change.
*/
for ( $i = 0; $i < $top_level_block_count; $i++ ) {
$output .= render_block( $blocks[ $i ] );
$blocks[ $i ] = null;
}
// If there are blocks in this content, we shouldn't run wpautop() on it later.

View File

@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '6.8.2-alpha-60434';
$wp_version = '6.8.2-alpha-60435';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.