fix: prevent OOM memory exhaustion on sites with many hooks - #6
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Pulse: PR has merge conflicts (likely due to PR #4 merging the aidevops init files). Please rebase onto main to resolve. |
Root causes identified and fixed (issue #2): 1. Inline JSON dump removed from render_debug_panel() The full profile dataset was serialised via wp_json_encode() and embedded as a <script> tag on every page load. On sites with many hooks this payload could be several MB, causing the PHP OOM at render time. Data is now fetched lazily via AJAX only when the panel is opened (dataLoaded guard prevents duplicate requests). 2. callback_aggregates cap enforced at collection time Previously only the final get_profile_data() return was sliced to 150 items, but the in-memory map grew without bound throughout the request. A new max_callbacks limit (default 500) stops new entries being created once the cap is reached. Existing entries continue to accumulate timing data. Configurable: add_filter('wp_hook_profiler_max_callbacks', fn() => 1000) 3. Per-plugin hooks array capped timing_data[$plugin]['hooks'] was an ever-growing array of every unique hook name seen for that plugin, causing O(hooks x plugins) memory growth. Capped at max_hooks_per_plugin (default 100). Configurable: add_filter('wp_hook_profiler_max_hooks_per_plugin', fn() => 200) 4. Proactive memory guard on_hook_start() now checks memory_get_usage(true) against a configurable fraction of PHP memory_limit (default 80%) and pauses profiling if the threshold is exceeded. A memory_paused flag is returned in get_profile_data() and shown as a warning banner in the UI. Configurable: add_filter('wp_hook_profiler_memory_threshold', fn() => 0.70) 5. plugins summary strips hooks array before returning get_profile_data() now returns a plugins_summary that omits the hooks array from each plugin entry — the UI does not use it and it was the largest contributor to the serialised payload size. UI: warning banners shown when memory_paused or callbacks_capped so users know the data is partial and how to tune the limits.
ca73d70 to
435920c
Compare
Summary
Fixes the PHP Fatal: Allowed memory size exhausted error reported in issue #2.
Five root causes were identified and fixed:
1. Inline JSON dump removed from
render_debug_panel()The full profile dataset was serialised via
wp_json_encode()and embedded as a<script>tag on every page load. On sites with many hooks this payload could be several MB, causing the PHP OOM at render time — before the user even opened the panel.Data is now fetched lazily via AJAX only when the panel is opened. A
dataLoadedguard prevents duplicate requests on subsequent opens.2.
callback_aggregatescap enforced at collection timePreviously only the final
get_profile_data()return was sliced to 150 items, but the in-memory map grew without bound throughout the request. A newmax_callbackslimit (default 500) stops new entries being created once the cap is reached. Existing entries continue to accumulate timing data;total_execution_timeis always accurate.3. Per-plugin hooks array capped
timing_data[$plugin]['hooks']was an ever-growing array of every unique hook name seen for that plugin, causing O(hooks × plugins) memory growth. Capped atmax_hooks_per_plugin(default 100).4. Proactive memory guard
on_hook_start()now checksmemory_get_usage(true)against a configurable fraction ofmemory_limit(default 80%) and pauses profiling if the threshold is exceeded. Amemory_pausedflag is returned inget_profile_data()and shown as a warning banner in the UI.5.
pluginssummary stripshooksarray before returningget_profile_data()now returns aplugins_summarythat omits thehooksarray from each plugin entry. The UI does not use it and it was the largest contributor to the serialised payload size.UI changes
memory_pausedorcallbacks_cappedso users know the data is partial and how to tune the limits.Files changed
inc/class-hook-profiler-engine.php— memory guard, caps, filter hooks, summary strippinginc/class-callback-wrapper.php— cap enforcement at collection time, hooks-per-plugin caphook-profiler.php— removed inline JSON dump fromrender_debug_panel()assets/profiler.js— lazy AJAX load,dataLoadedguard, memory/cap warning bannersassets/profiler.css— warning notice stylesREADME.md— troubleshooting section updated with filter hook examplesCloses #2