Skip to content

Commit 723d8e4

Browse files
committed
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. git-svn-id: https://develop.svn.wordpress.org/branches/6.8@60435 602fd350-edb4-49c9-b593-d223f7449a82
1 parent f3e7d3a commit 723d8e4

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

src/wp-includes/blocks.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2404,11 +2404,32 @@ function parse_blocks( $content ) {
24042404
* @return string Updated post content.
24052405
*/
24062406
function do_blocks( $content ) {
2407-
$blocks = parse_blocks( $content );
2408-
$output = '';
2407+
$blocks = parse_blocks( $content );
2408+
$top_level_block_count = count( $blocks );
2409+
$output = '';
24092410

2410-
foreach ( $blocks as $block ) {
2411-
$output .= render_block( $block );
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

24142435
// If there are blocks in this content, we shouldn't run wpautop() on it later.

0 commit comments

Comments
 (0)