[wp-trac] [WordPress Trac] #55206: wp core api memory leaks

WordPress Trac noreply at wordpress.org
Sun Feb 20 05:37:43 UTC 2022


#55206: wp core api memory leaks
--------------------------+-----------------------------
 Reporter:  sllimrovert   |      Owner:  (none)
     Type:  defect (bug)  |     Status:  assigned
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  Database      |    Version:  trunk
 Severity:  normal        |   Keywords:
  Focuses:                |
--------------------------+-----------------------------
 I've experienced the following two memory leaks in WP core.  One involves
 $wpdb when `SAVEQUERIES` is defined truthy, and the other involves
 `$wp_object_cache` growing as a consequence of calling core api functions
 that themselves save to the object cache.  Both have happened for me in
 cases where I'm doing large batch processing involving thousands or tens
 of thousands of posts.  I've had memory usage exceed 512MB and cause
 crashes.

 I'm including unit tests here showing each memory leak and also the fix
 that I've used to prevent the memory leak and keep my batch jobs running.

 {{{#!php
 <?php

 /**
  * Class WP_Memory_Leak_Tests
  *
  * This class tests two cases that cause memory leaks in WordPress that
 could
  * lead to crashes, particularly in CLI jobs that work on larger batches.
 For
  * each of the cases ( one for the wpdb class and one for the global
  * $wp_object_cache ), we perform some seemingly innocuous task many times
 -
  * enough times to require that PHP allocate more memory because of a
 specific
  * action.
  *
  * Neither of the tests here show a particularly large memory increase,
 but I've
  * personally had both occur for me on large jobs hitting WP API
 functions.  The
  * one with $wpdb->queries particularly has a tendency to blow up.
  */
 class WP_Memory_Leak_Tests extends WP_UnitTestCase {

         /**
          * This tests a condition which exposes a memory leak in the WPDB
 class.
          * If 'SAVEQUERIES' is defined as truthy, then the $wpdb->queries
 property
          * can grow indefinitely.
          */
         public function test_WPDB_Memory_Leak() {

                 // Once a constant is defined, it can't be undefined, it's
 often defined in dev or staging environments.
                 define( 'SAVEQUERIES', true );

                 // I'll just start my cron job to read the import file
 I've got.  It's
                 // got a decent number of records.
                 $number_of_records = 1000;

                 global $wpdb;
                 $memory = memory_get_usage( true );
                 $peak   = memory_get_peak_usage( true );
                 foreach ( [ 'first', 'second' ] as $pass ) {
                         // first pass through, we'll apply a fix for this
 memory leak.
                         // second pass through, we'll bypass the fix and
 the tests will fail.
                         for ( $i = 1; $i <= $number_of_records; $i ++ ) {
                                 if ( 'first' === $pass ) {
                                         $wpdb->queries = [];
                                 }

                                 // for this test, we'll do direct calls to
 $wpdb
                                 $wpdb->query( $wpdb->prepare( "SELECT *
 FROM $wpdb->posts WHERE ID = %d", $i ) );
                         }
                         $this->assertEquals( $memory, memory_get_usage(
 true ), "$pass pass" );
                         $this->assertEquals( $peak, memory_get_peak_usage(
 true ), "$pass pass" );
                 }

         }

         /**
          * This tests a condition which exposes a memory leak in wp cache
 API.  If
          * a large batch job attempts to do a lot of something that ends
 up caching
          * things ( like, for example, get_post or wp_insert_post ), then
 unless
          * the cache is flushed regularly, the memory usage grows
 indefinitely.
          */
         public function test_WP_Cache_Memory_Leak() {

                 // I'll just start my cron job to read the import file
 I've got.  It's
                 // got a decent number of records.
                 $number_of_records = 1000;

                 global $wpdb;
                 $memory = memory_get_usage( true );
                 $peak   = memory_get_peak_usage( true );
                 foreach ( [ 'first', 'second' ] as $pass ) {
                         // first pass through, we'll apply a fix for this
 memory leak.
                         // second pass through, we'll bypass the fix and
 the tests will fail.
                         for ( $i = 1; $i <= $number_of_records; $i ++ ) {
                                 if ( 'first' === $pass ) {
                                         wp_cache_flush();
                                 }

                                 // Because our last test defined
 'SAVEQUERIES', we need to
                                 // always apply this fix, otherwise that
 memory leak manifests.
                                 // With us doing a core API function
 `wp_insert_post`, the number
                                 // of queries is quite large and memory
 __really__ grows.
                                 $wpdb->queries = [];

                                 // let's say we're inserting posts, maybe
 from an excel file.
                                 // this caches some things, so
 $wp_object_cache grows.
                                 wp_insert_post([
                                         'post_type' => 'post',
                                         'post_title' => "post $i",
                                         'post_content' => "pass $pass"
                                 ]);
                         }
                         $this->assertEquals( $memory, memory_get_usage(
 true ), "$pass pass" );
                         $this->assertEquals( $peak, memory_get_peak_usage(
 true ), "$pass pass" );
                 }

         }

 }

 }}}

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/55206>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list