ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ ಹತ್ತು ನಿಮಿಷಗಳ ಕಾಲ ಸರಿಯಾಗಿ ಚಲಿಸುತ್ತದೆ. ನಂತರ ಸ್ಕ್ರೋಲ್ ಆಗುವುದು ಕಷ್ಟವಾಗುತ್ತದೆ (sticky). ಅರ್ಧ ಗಂಟೆಯ ನಂತರ ಟ್ಯಾಬ್ ಒಂದು ಗಿಗಾಬೈಟ್ಗೆ ತಲುಪುತ್ತದೆ. ಅಂತಿಮವಾಗಿ, ಔಟ್-ಆಫ್-ಮೆಮೊರಿ (out-of-memory) ದೋಷದೊಂದಿಗೆ ಪುಟವು ಸ್ಥಗಿತಗೊಳ್ಳುತ್ತದೆ ಮತ್ತು ಅದನ್ನು ತೋರಿಸಲು ನಿಮ್ಮ ಬಳಿ ಯಾವುದೇ ಸ್ಟ್ಯಾಕ್ ಟ್ರೇಸ್ (stack trace) ಇರುವುದಿಲ್ಲ.
ಇದು ರೆಂಡರ್ ಪರ್ಫಾರ್ಮೆನ್ಸ್ (render performance) ಸಮಸ್ಯೆಯಲ್ಲ. React DevTools Profiler ಸುಮ್ಮನೆ ಕಾಣಿಸಬಹುದು ಏಕೆಂದರೆ ಸಮಸ್ಯೆ ಎಂದರೆ ಘಟಕಗಳು (components) ಎಷ್ಟು ಬಾರಿ ಮರು-ಚಿತ್ರಣಗೊಳ್ಳುತ್ತವೆ (redraw) ಎಂಬುದಲ್ಲ. ಸಮಸ್ಯೆ ಎಂದರೆ ಅವು ಅನ್ಮೌಂಟ್ (unmount) ಆದ ನಂತರ ಯಾವುದು ಜೀವಂತವಾಗಿ ಉಳಿಯುತ್ತದೆ ಎಂಬುದು. JavaScript heap ನಲ್ಲಿ ಎಲ್ಲೋ ಇರುವ ಒಂದು ಅಲೆಯುವ ರೆಫರೆನ್ಸ್ (stray reference), ಇಡೀ DOM ನೋಡ್ಗಳು, ಕ್ಲೋಸರ್ಸ್ಗಳು (closures) ಮತ್ತು ಸ್ಟೇಟ್ (state) ಅನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುತ್ತದೆ. ಬ್ರೌಸರ್ ಇವುಗಳಲ್ಲಿ ಯಾವುದನ್ನೂ ಮರಳಿ ಪಡೆಯಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ, ಆದ್ದರಿಂದ ಪ್ರಕ್ರಿಯೆಯು ಕುಸಿದು ಹೋಗುವವರೆಗೆ ಮೆಮೊರಿ ಏರುತ್ತಲೇ ಇರುತ್ತದೆ.
ನಿಮ್ಮ ಸೋರ್ಸ್ ಕೋಡ್ ಅನ್ನು ಓದುವುದರಿಂದ ಈ ಲೀಕ್ (leak) ಪತ್ತೆಯಾಗುವುದಿಲ್ಲ. ನೀವು ಅನ್ಮೌಂಟ್ ಆಗಿದೆ ಎಂದು ಭಾವಿಸುವ ಮತ್ತು ಗಾರ್ಬೇಜ್ ಕಲೆಕ್ಟರ್ (garbage collector) ವಾಸ್ತವವಾಗಿ ನೋಡುವ ನಡುವಿನ ಅಂತರದಲ್ಲಿ ಈ ಬಗ್ ಅಡಗಿದೆ. V8 ಕೇವಲ ಶೂನ್ಯ ರಿಟೈನಿಂಗ್ ಪಾತ್ಗಳನ್ನು (retaining paths) ಹೊಂದಿರುವ ಆಬ್ಜೆಕ್ಟ್ಗಳನ್ನು ಮಾತ್ರ ಬಿಡುಗಡೆ ಮಾಡುತ್ತದೆ. ಒಂದು ಅಲೆಯುವ ಇವೆಂಟ್ ಲಿಸನರ್ (event listener), ಕ್ಲಿಯರ್ ಮಾಡದ ಅಬ್ಸರ್ವರ್ (observer), ಅಥವಾ ದೀರ್ಘಕಾಲದ ಕ್ಲೋಸರ್ (closure) ಒಂದು ಫೈಬರ್ ಅಥವಾ DOM ನೋಡ್ಗೆ ಕೇವಲ ಒಂದು ಪಾಯಿಂಟರ್ ಅನ್ನು ಹೊಂದಿದ್ದರೂ ಸಹ, ಇಡೀ ಕಾಂಪೊನೆಂಟ್ ಸಬ್ಟ್ರೀ (component subtree) ಉಳಿಯುತ್ತದೆ. ನೀವು ಒಂದು ಮಾಡಲ್ ಅನ್ನು ಅನ್ಮೌಂಟ್ ಮಾಡುತ್ತೀರಿ, ಆದರೆ ಅದರ ಡಿಟ್ಯಾಚ್ಡ್ ನೋಡ್ಗಳು (detached nodes) ಮೆಮೊರಿಯಲ್ಲಿ ಉಳಿಯುತ್ತವೆ ಏಕೆಂದರೆ window ಮೇಲಿರುವ ಲಿಸನರ್ ಇನ್ನೂ ಆ ಮಾಡಲ್ನ ಒಳಗಡೆ ವ್ಯಾಖ್ಯಾನಿಸಲಾದ ಹ್ಯಾಂಡ್ಲರ್ಗೆ (handler) ಸೂಚಿಸುತ್ತದೆ.
ಲೀಕ್ ಎಲ್ಲಿದೆ ಎಂದು ಸಾಬೀತುಪಡಿಸಲು ನೀವು ಎಡಿಟರ್ ಅನ್ನು ನೋಡುವ ಬದಲು ಹೀಪ್ (heap) ಅನ್ನು ನೋಡಬೇಕಾಗುತ್ತದೆ.
ಹೀಪ್ ಏಕೆ ಸತ್ಯವನ್ನು ಹೇಳುತ್ತದೆ
Chrome DevTools ಗಾರ್ಬೇಜ್ ಕಲೆಕ್ಟರ್ ಏನನ್ನು ನೋಡುತ್ತದೆಯೋ ಅದಕ್ಕೆ ನಿಮಗೆ ನೇರ ಕಿಟಕಿಯನ್ನು ನೀಡುತ್ತದೆ. ಮೆಮೊರಿ ಟ್ಯಾಬ್ (Memory tab) ಹೀಪ್ ಸ್ನ್ಯಾಪ್ಶಾಟ್ಗಳನ್ನು (heap snapshots) ದಾಖಲಿಸಬಹುದು: ಅಂದರೆ JavaScript ಮೆಮೊರಿಯಲ್ಲಿ ಪ್ರಸ್ತುತ ಇರುವ ಪ್ರತಿಯೊಂದು ಆಬ್ಜೆಕ್ಟ್, DOM ನೋಡ್ ಮತ್ತು ಕ್ಲೋಸರ್ನ ಸಂಪೂರ್ಣ ಪಟ್ಟಿ. ಸಂಶಯಾಸ್ಪದ ಲೀಕ್ ಆಗುವ ಮೊದಲು ಮತ್ತು ನಂತರದ ಎರಡು ಸ್ನ್ಯಾಪ್ಶಾಟ್ಗಳನ್ನು ಹೋಲಿಸುವ ಮೂಲಕ, ಯಾವ ಆಬ್ಜೆಕ್ಟ್ಗಳು ಅಳಿಸಿ ಹೋಗಲು ವಿಫಲವಾದವು ಎಂಬುದನ್ನು ನೀವು ನಿಖರವಾಗಿ ಪ್ರತ್ಯೇಕಿಸಬಹುದು.
ಇದು ಕೇವಲ ಸೈದ್ಧಾಂತಿಕ ವಿಷಯವಲ್ಲ. ಒಂದು ಲೀಕ್ ಆದ React ಕಾಂಪೊನೆಂಟ್ ಸಾವಿರಾರು ಡಿಟ್ಯಾಚ್ಡ್ HTMLElement ಆಬ್ಜೆಕ್ಟ್ಗಳನ್ನು ಉಳಿಸಿಕೊಳ್ಳಬಹುದು. ಆ ಆಬ್ಜೆಕ್ಟ್ಗಳು ಈಗ ದೃಶ್ಯ ದಾಖಲೆಗೆ (visible document) ಅಂಟಿಕೊಂಡಿರುವುದಿಲ್ಲ, ಆದರೆ JavaScript ರೆಫರೆನ್ಸ್ಗಳು ಅವುಗಳನ್ನು ಸಂಗ್ರಹಿಸದಂತೆ (collected) ತಡೆಯುತ್ತವೆ. ಅವು ಹೋಲಿಕೆಯ ವೀಕ್ಷಣೆಯಲ್ಲಿ (comparison view) Detached HTMLElement ಎಂಬ ಕನ್ಸ್ಟ್ರಕ್ಟರ್ ಹೆಸರಿನೊಂದಿಗೆ ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತವೆ. ಅವುಗಳು ಹೆಚ್ಚಾಗುತ್ತಿರುವುದನ್ನು ನೀವು ನೋಡಿದಾಗ, ನೀವು ನಿಮ್ಮ ಲೀಕ್ ಅನ್ನು ಪತ್ತೆಹಚ್ಚಿದ್ದೀರಿ ಎಂದರ್ಥ.
Chrome DevTools ವರ್ಕ್ಫ್ಲೋ (Workflow)
ಸ್ವಚ್ಛವಾಗಿ ಪ್ರಾರಂಭಿಸಿ. ಸಂಬಂಧವಿಲ್ಲದ ಬ್ರೌಸರ್ ಟ್ಯಾಬ್ಗಳನ್ನು ಮುಚ್ಚಿ, ಸಂಬಂಧವಿಲ್ಲದ ಎಕ್ಸ್ಟೆನ್ಶನ್ಗಳನ್ನು (extensions) ಅಸಕ್ರಿಯಗೊಳಿಸಿ ಮತ್ತು ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ ಸ್ಥಿರ ಸ್ಥಿತಿಗೆ (steady state) ಬರುವಂತೆ ಬಿಡಿ. Chrome DevTools ತೆರೆಯಿರಿ, Memory ಟ್ಯಾಬ್ಗೆ ಹೋಗಿ ಮತ್ತು Heap snapshot ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ. Take snapshot ಮೇಲೆ ಕ್ಲಿಕ್ ಮಾಡಿ. ಈ ಬೇಸ್ಲೈನ್ (baseline) ನಿಮ್ಮ ಆರಂಭಿಕ ಮೆಮೊರಿ ಫುಟ್ಪ್ರಿಂಟ್ ಅನ್ನು ಸೆರೆಹಿಡಿಯುತ್ತದೆ.
ಈಗ ನೀವು ಸಂಶಯಪಡುವ ಅದೇ ಬಳಕೆದಾರ ಕ್ರಿಯೆಯನ್ನು (user action) ಮಾಡಿ. ಆ ಭಾರವಾದ ಮಾಡಲ್ ಅನ್ನು ತೆರೆಯಿರಿ ಮತ್ತು ಮುಚ್ಚಿ. ವಿಜೆಟ್ ಅನ್ನು ಮೌಂಟ್ ಮತ್ತು ಅನ್ಮೌಂಟ್ ಮಾಡಿ. ರೂಟ್ಗೆ (route) ಹೋಗಿ ಮತ್ತು ವಾಪಸ್ ಬನ್ನಿ. UI ತನ್ನ ಮೂಲ ದೃಶ್ಯ ಸ್ಥಿತಿಗೆ ಮರಳಿದ ನಂತರ, Memory ಟ್ಯಾಬ್ನಲ್ಲಿರುವ ಕಸದ ಬುಟ್ಟಿ (trash can) ಐಕಾನ್ ಮೇಲೆ ಕ್ಲಿಕ್ ಮಾಡಿ. ಇದು ಗ್ಲೋಬಲ್ ಗಾರ್ಬೇಜ್ ಕಲೆಕ್ಷನ್ ಪ್ರಕ್ರಿಯೆಯನ್ನು ಬಲವಂತವಾಗಿ ನಡೆಸುತ್ತದೆ. ರೆಂಡರ್ ಸೈಕಲ್ನ ತಾತ್ಕಾಲಿಕ ಆಬ್ಜೆಕ್ಟ್ಗಳು ಅಳಿಸಿ ಹೋಗಬೇಕು. ಉಳಿದಿರುವ ಯಾವುದಾದರೂ ಲೀಕ್ಗೆ ನಿಜವಾದ ಅಭ್ಯರ್ಥಿಯಾಗಿರುತ್ತದೆ.
ಮತ್ತೆ Take snapshot ಮೇಲೆ ಕ್ಲಿಕ್ ಮಾಡಿ. ಈಗ ನಿಮ್ಮ ಬಳಿ ಮೆಮೊರಿಯ ಎರಡು ಫೋಟೋಗಳಿವೆ. ವೀಕ್ಷಣೆಯನ್ನು Summary ನಿಂದ Comparison ಗೆ ಬದಲಾಯಿಸಿ. ಹೋಲಿಕೆಯ ವ್ಯಾಪ್ತಿಯನ್ನು (comparison scope) ಮೊದಲ ಸ್ನ್ಯಾಪ್ಶಾಟ್ಗೆ ಹೊಂದಿಸಿ. ಈ ಟೂಲ್ ರನ್ಟೈಮ್ನ ಗೊಂದಲಗಳನ್ನು ತೆಗೆದುಹಾಕಿ, ಎರಡು ಕ್ಯಾಪ್ಚರ್ಗಳ ನಡುವೆ ಏನನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆಯೋ ಅದನ್ನು ಮಾತ್ರ ನಿಮಗೆ ತೋರಿಸುತ್ತದೆ.
Delta ಮೂಲಕ ವಿಂಗಡಿಸಿ (Sort). ಹೆಚ್ಚಾದ ಆಬ್ಜೆಕ್ಟ್ ಸಂಖ್ಯೆಗಳನ್ನು ಗಮನಿಸಿ. Detached HTMLElement, Array, Function, ಅಥವಾ ನಿಮ್ಮ ಸ್ವಂತ ಕೋಡ್ಬೇಸ್ನ ಹೆಸರಿಸಿದ ಕ್ಲಾಸ್ ಇನ್ಸ್ಟೆನ್ಸ್ (class instances) ನಂತಹ ಕನ್ಸ್ಟ್ರಕ್ಟರ್ಗಳ ಬಗ್ಗೆ ವಿಶೇಷ ಗಮನಹರಿಸಿ. ಹೆಚ್ಚುತ್ತಿರುವ ಡೆಲ್ಟಾ (delta) ಎಂದರೆ ನಿಮ್ಮ ಕ್ರಿಯೆಯ ಸಮಯದಲ್ಲಿ ಆಬ್ಜೆಕ್ಟ್ಗಳು ರಚಿಸಲ್ಪಟ್ಟಿವೆ ಮತ್ತು ನಂತರ ಸಂಗ್ರಹಿಸಲ್ಪಟ್ಟಿಲ್ಲ ಎಂದರ್ಥ.
ರಿಟೈನಿಂಗ್ ಪಾತ್ (Retaining Path) ಅನ್ನು ಪತ್ತೆಹಚ್ಚುವುದು
ನೀವು ಲೀಕ್ ಆದ ಎಲಿಮೆಂಟ್ ಅನ್ನು ಪತ್ತೆಹಚ್ಚಿದಾಗ, ಅದನ್ನು ಆಯ್ಕೆಮಾಡಿ. ಕೆಳಗಿನ ಪ್ಯಾನಲ್ ರಿಟೈನಿಂಗ್ ಪಾತ್ ಅನ್ನು ಪ್ರದರ್ಶಿಸುತ್ತದೆ: ಇದು ಈ ಆಬ್ಜೆಕ್ಟ್ ಏಕೆ ಇನ್ನೂ ಜೀವಂತವಾಗಿದೆ ಎಂಬುದನ್ನು ವಿವರಿಸುವ ರೆಫರೆನ್ಸ್ಗಳ ಸರಪಳಿ. ಈ ಸರಪಳಿಯು ಒಂದು ಡಿಟ್ಯಾಚ್ಡ್ div ನಿಂದ ಪ್ರಾರಂಭವಾಗಿ React ಆಂತರಿಕ ಗುಣಲಕ್ಷಣಗಳ (internal properties) ಮೂಲಕ, ಒಂದು ಕ್ಲೋಸರ್ನೊಳಗೆ ಹೋಗಿ, ಅಂತಿಮವಾಗಿ ನಿಮ್ಮ ಕಾಂಪೊನೆಂಟ್ಗಳಲ್ಲಿ ಒಂದರ ಒಳಗಡೆ ನೋಂದಾಯಿಸಲಾದ ಇವೆಂಟ್ ಲಿಸನರ್ಗೆ ತಲುಪಬಹುದು. ಸರಪಳಿಯ ಆ ಕೊನೆಯ ಕೊಂಡಿಯೇ ನಿಮ್ಮ ಲೈನ್ ನಂಬರ್ (line number).
ಇಲ್ಲಿ ನೀವು ರೋಗನಿರ್ಣಯದಿಂದ (diagnosis) ಮೂಲ ಕಾರಣದ (root cause) ಕಡೆಗೆ ಸಾಗುತ್ತೀರಿ. ರಿಟೈನಿಂಗ್ ಪಾತ್ window.addEventListener ನಲ್ಲಿ ಕೊನೆಗೊಂಡರೆ, ಒಂದು ಗ್ಲೋಬಲ್ ಲಿಸನರ್ ನಿಮ್ಮ ಕಾಂಪೊನೆಂಟ್ ಅನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಂಡಿದೆ ಎಂದು ನೀವು ತಿಳಿಯಬಹುದು. ಅದು IntersectionObserver ಇನ್ಸ್ಟೆನ್ಸ್ನಲ್ಲಿ ಕೊನೆಗೊಂಡರೆ, ಗಾರ್ಬೇಜ್ ಕಲೆಕ್ಟ್ ಆಗಬೇಕಿದ್ದ ನೋಡ್ ಅನ್ನು ಅಬ್ಸರ್ವರ್ ಇನ್ನೂ ಗಮನಿಸುತ್ತಿದೆ ಎಂದು ನೀವು ತಿಳಿಯಬಹುದು.
React ನಲ್ಲಿನ ಸಾಮಾನ್ಯ ಕಾರಣಗಳು
React ನಲ್ಲಿನ ಮೆಮೊರಿ ಲೀಕ್ಗಳು ಸಾಮಾನ್ಯವಾಗಿ ಮೂರು ಮಾದರಿಗಳಲ್ಲಿರುತ್ತವೆ.
ಅನಾಥ ಗ್ಲೋಬಲ್ ಲಿಸನರ್ಗಳು (Orphaned global listeners). ಸ್ಕ್ರಾಲ್ ಸ್ಥಾನ (scroll position), ಕೀ ಪ್ರೆಸ್ಗಳು ಅಥವಾ ರಿಸೈಜ್ ಇವೆಂಟ್ಗಳನ್ನು ಟ್ರ್ಯಾಕ್ ಮಾಡಲು useEffect ஆனது window ಅಥವಾ document ಗೆ ಹೂಕ್ ಆಗುತ್ತದೆ. ಒಂದು ವೇಳೆ ಆ ಎಫೆಕ್ಟ್ removeEventListener ಅನ್ನು ಕರೆಯುವ ಕ್ಲೀನಪ್ ಫಂಕ್ಷನ್ ಅನ್ನು (cleanup function) ಹಿಂತಿರುಗಿಸದಿದ್ದರೆ, ಆ ಲಿಸನರ್ ಪುಟದ ಜೀವಿತಾವಧಿಯವರೆಗೆ ಉಳಿಯುತ್ತದೆ. ಲಿಸನರ್ ಒಂದು ಕ್ಲೋಸರ್ ಆಗಿರುವುದರಿಂದ, React ಕಾಂಪೊನೆಂಟ್ ಅನ್ನು ಅನ್ಮೌಂಟ್ ಮಾಡಿದ ನಂತರವೂ ಅದು ಇಡೀ ಕಾಂಪೊನೆಂಟ್ ಸ್ಕೋಪ್ ಅನ್ನು ಜೀವಂತವಾಗಿರಿಸುತ್ತದೆ.
ಸ್ವಚ್ಛಗೊಳಿಸದ ಅಬ್ಸರ್ವರ್ಗಳು. IntersectionObserver ಮತ್ತು ResizeObserver ಶಕ್ತಿಯುತವಾಗಿವೆ, ಆದರೆ ಅವು React ನ ನಿಯಂತ್ರಣದ ಹೊರಗೆ ನೇಟಿವ್ ರೆಫರೆನ್ಸ್ಗಳನ್ನು (native references) ಸೃಷ್ಟಿಸುತ್ತವೆ. ನೀವು ಒಂದು ಕಾಂಪೊನೆಂಟ್ನೊಳಗೆ ಅಬ್ಸರ್ವರ್ ಅನ್ನು ಇನ್ಸ್ಟಾಂಟಿಯೇಟ್ ಮಾಡಿ (instantiate) ಮತ್ತು ಕ್ಲೀನಪ್ ಹಂತದಲ್ಲಿ (cleanup phase) disconnect() ಅನ್ನು ಕರೆಯಲು ಮರೆತರೆ, ಅಬ್ಸರ್ವರ್ ಟಾರ್ಗೆಟ್ DOM ನೋಡ್ ಅನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುತ್ತದೆ, ಮತ್ತು ಆ DOM ನೋಡ್ React fibers, props ಮತ್ತು state ಅನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುತ್ತದೆ.
ಕ್ಲೋಸರ್ ಟ್ರ್ಯಾಪ್ಗಳು. ನೀವು ಒಂದು ಕಾಂಪೊನೆಂಟ್ನೊಳಗೆ ಫಂಕ್ಷನ್ ಅನ್ನು ವ್ಯಾಖ್ಯಾನಿಸಿ (define) ಅದನ್ನು ಥರ್ಡ್-ಪಾರ್ಟಿ ಲೈಬ್ರರಿ, ಗ್ಲೋಬಲ್ ಕ್ಯಾಶ್ ಅಥವಾ setTimeout ಗೆ ವರ್ಗಾಯಿಸಿದಾಗ, ಆ ಫಂಕ್ಷನ್ ತನ್ನ ಲೆಕ್ಸಿಕಲ್ ಸ್ಕೋಪ್ನಲ್ಲಿರುವ (lexical scope) ಪ್ರತಿಯೊಂದು ವೇರಿಯೇಬಲ್ ಅನ್ನು ಒಳಗೊಳ್ಳುತ್ತದೆ. ಆ ಬಾಹ್ಯ ಮಾಲೀಕ (external owner) ಆ ಫಂಕ್ಷನ್ ಅನ್ನು ಉಳಿಸಿಕೊಂಡರೆ, ಅದು ನಿಮ್ಮ ಇಡೀ ಕಾಂಪೊನೆಂಟ್ ಸ್ಕೋಪ್ ಅನ್ನು ತನ್ನೊಂದಿಗೆ ಉಳಿಸಿಕೊಳ್ಳುತ್ತದೆ.
ನಿಜವಾಗಿಯೂ ಕೆಲಸ ಮಾಡುವ ಕ್ಲೀನಪ್ ಪ್ಯಾಟರ್ನ್ಗಳು
ಲೀಕ್ ಅನ್ನು ಸರಿಪಡಿಸುವುದು ಎಂದರೆ ಸ್ನ್ಯಾಪ್ಶಾಟ್ನಲ್ಲಿ ನೀವು ಕಂಡುಕೊಂಡ ಪ್ರತಿಯೊಂದು ರಿಟೈನಿಂಗ್ ಪಾತ್ (retaining path) ಅನ್ನು ಕತ್ತರಿಸುವುದು ಎಂದರ್ಥ.
ಯಾವಾಗಲೂ useEffect ನಿಂದ ಕ್ಲೀನಪ್ ಫಂಕ್ಷನ್ ಅನ್ನು ರಿಟರ್ನ್ ಮಾಡಿ. ನೀವು ಎಫೆಕ್ಟ್ನಲ್ಲಿ ಲಿಸನರ್ ಅನ್ನು ಸೇರಿಸಿದರೆ, ಅದನ್ನು ಅಲ್ಲಿಯೇ ತೆಗೆದುಹಾಕಿ.
ನೀವು DOM ಅಥವಾ window ಗೆ ಅಟ್ಯಾಚ್ ಮಾಡುವ ಯಾವುದೇ ಹ್ಯಾಂಡ್ಲರ್ಗಾಗಿ useCallback ಬಳಸಿ. ಇಲ್ಲದಿದ್ದರೆ, ಪ್ರತಿ ರೆಂಡರ್ ಕೂಡ ಹೊಸ ಫಂಕ್ಷನ್ ರೆಫರೆನ್ಸ್ ಅನ್ನು ಸೃಷ್ಟಿಸುತ್ತದೆ. ನೀವು ಒಂದು ರೆಫರೆನ್ಸ್ನೊಂದಿಗೆ addEventListener ಅನ್ನು ಕರೆದು, ನಂತರ ಬೇರೆ ರೆಫರೆನ್ಸ್ನೊಂದಿಗೆ removeEventListener ಅನ್ನು ಕರೆದರೆ, ಆ ತೆಗೆದುಹಾಕುವ ಪ್ರಕ್ರಿಯೆಯು ಯಾವುದೇ ಎಚ್ಚರಿಕೆ ಇಲ್ಲದೆ ವಿಫಲವಾಗುತ್ತದೆ. ಮೂಲ ಲಿಸನರ್ window ನಲ್ಲಿ ಶಾಶ್ವತವಾಗಿ ಉಳಿಯುತ್ತದೆ. useCallback ರೆಫರೆನ್ಸ್ ಅನ್ನು ಸ್ಥಿರವಾಗಿರಿಸುತ್ತದೆ, ಇದರಿಂದಾಗಿ add ಮತ್ತು remove ನಿಖರವಾಗಿ ಹೊಂದಿಕೆಯಾಗುತ್ತವೆ.
ಅಬ್ಸರ್ವರ್ಗಳನ್ನು ಸಹ ಅದೇ ಶಿಸ್ತಿನಿಂದ ನಿರ್ವಹಿಸಿ. ಅಬ್ಸರ್ವರ್ ಇನ್ಸ್ಟೆನ್ಸ್ ಅನ್ನು ಎಫೆಕ್ಟ್ನೊಳಗೆ ಒಂದು ref ಅಥವಾ ಲೋಕಲ್ ವೇರಿಯೇಬಲ್ನಲ್ಲಿ ಸಂಗ್ರಹಿಸಿ. ಕ್ಲೀನಪ್ ಫಂಕ್ಷನ್ನಲ್ಲಿ, observer.disconnect() ಅನ್ನು ಕರೆಯಿರಿ. ಕಾಂಪೊನೆಂಟ್ ಅನ್ಮೌಂಟ್ (unmounting) ಆಗುವುದರಿಂದ ಅಬ್ಸರ್ವರ್ ಕೊನೆಗೊಳ್ಳುತ್ತದೆ ಎಂದು ಭಾವಿಸಬೇಡಿ. ಅದು ಹಾಗೆ ಆಗುವುದಿಲ್ಲ.
ನಿಮ್ಮ ಕಾಂಪೊನೆಂಟ್ ಯಾವುದನ್ನಾದರೂ ಗ್ಲೋಬಲ್ ನೇಮ್ಸ್ಪೇಸ್ ಅಥವಾ ಸಿಂಗಲ್ಟನ್ ಸರ್ವಿಸ್ಗೆ ಪ್ರಕಟಿಸಿದರೆ (publishes), ಅನ್ಮೌಂಟ್ ಮಾಡುವಾಗ ಆ ರೆಫರೆನ್ಸ್ಗಳನ್ನು ಡಿಲೀಟ್ ಮಾಡಿ. ಒಂದು ಆಬ್ಜೆಕ್ಟ್ ನಿಜವಾಗಿಯೂ ತಲುಪಲು ಸಾಧ್ಯವಾಗದಿದ್ದಾಗ ಮಾತ್ರ V8 engine ಮೆಮೊರಿಯನ್ನು ಮರುಪಡೆಯಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ. window ನಲ್ಲಿ ಒಂದು ಹೂಕ್ ಅನ್ನು ಅಥವಾ module-level Map ನಲ್ಲಿ ಒಂದು ಎಂಟ್ರಿಯನ್ನು ಬಿಡುವುದು ಒಂದು ಅದೃಶ್ಯ ಸೇತುವೆಯನ್ನು ಸೃಷ್ಟಿಸುತ್ತದೆ, ಇದು ಹೀಪ್ (heap) ಬೆಳೆಯುತ್ತಲೇ ಇರಲು ಕಾರಣವಾಗುತ್ತದೆ.
ನಿಜವಾದ ಸಾರಾಂಶ
ಮೆಮೊರಿ ಲೀಕ್ಗಳು ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ತಕ್ಷಣವೇ ಕ್ರ್ಯಾಶ್ ಮಾಡುವುದಿಲ್ಲ. ದೀರ್ಘ ಬಳಕೆದಾರರ ಸೆಷನ್ಗಳ ಸಮಯದಲ್ಲಿ ಅವು ಒಂದೊಂದಾಗಿ ಡಿಟ್ಯಾಚ್ಡ್ ನೋಡ್ಗಳನ್ನು (detached nodes) ಸಂಗ್ರಹಿಸುತ್ತವೆ. ಇದಕ್ಕೆ ಪರಿಹಾರವು ಲೈಬ್ರರಿ ಅಪ್ಗ್ರೇಡ್ ಅಥವಾ ಕಂಪೈಲರ್ ಫ್ಲಾಗ್ ಅಲ್ಲ. ಇದು ಹೀಪ್ ಸ್ನ್ಯಾಪ್ಶಾಟ್ಗಳೊಂದಿಗೆ (heap snapshots) ನಿಮ್ಮ ಕ್ಲೀನಪ್ ಲಾಜಿಕ್ ಅನ್ನು ಸಾಬೀತುಪಡಿಸುವ ಅಭ್ಯಾಸವಾಗಿದೆ.
ಒಂದು ಬೇಸ್ಲೈನ್ (baseline) ತೆಗೆದುಕೊಳ್ಳಿ, ಸಂಶಯಾಸ್ಪದ ಫ್ಲೋ ಅನ್ನು ಟ್ರಿಗ್ಗರ್ ಮಾಡಿ, ಗಾರ್ಬೇಜ್ ಕಲೆಕ್ಷನ್ ಅನ್ನು ಫೋರ್ಸ್ ಮಾಡಿ ಮತ್ತು ಹೋಲಿಸಿ. ವ್ಯತ್ಯಾಸವು (delta) ಹೆಚ್ಚಳವನ್ನು ತೋರಿಸಿದರೆ, ರಿಟೈನಿಂಗ್ ಪಾತ್ ಅನ್ನು ಪರೀಕ್ಷಿಸಿ, ಇರಬಾರದು ಎಂದುಕೊಂಡ ಲಿಸನರ್ ಅಥವಾ ಅಬ್ಸರ್ವರ್ ಅನ್ನು ಹುಡುಕಿ ಮತ್ತು ರೆಫರೆನ್ಸ್ ಅನ್ನು ಕತ್ತರಿಸಿ. ಪರೀಕ್ಷೆಯನ್ನು ಮತ್ತೆ ರನ್ ಮಾಡಿ. ವ್ಯತ್ಯಾಸವು ಸ್ಥಿರವಾಗಿದ್ದಾಗ, ನೀವು ಅದನ್ನು ನಿಜವಾಗಿಯೂ ಪರಿಹರಿಸಿದ್ದೀರಿ ಎಂದರ್ಥ. ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ ಸ್ಪಂದನೀಯವಾಗಿ (responsive) ಇರುತ್ತದೆ ಮತ್ತು ನಿಮ್ಮ ಬಳಕೆದಾರರು ಫ್ರೀಜ್ ಆದ ಬ್ರೌಸರ್ ಟ್ಯಾಬ್ನಿಂದಾಗಿ ತಮ್ಮ ಕೆಲಸವನ್ನು ಕಳೆದುಕೊಳ್ಳುವುದಿಲ್ಲ.
