Проблеми пошуку витоку пам'яті у веб-додатку за допомогою Chrome DevTools

Браузер Google Chrome поставляється з чудовими інструментами для розробника, вони ж є в Яндекс.Браузері, новій Опері, і в інших браузерах, заснованих на базі Chromium.

Серед них є приголомшливі інструменти для роботи з пам'яттю, ознайомитися з якими можна в статті користувача Panya - «Як знаходити і усувати витоки пам'яті на прикладі Яндекс.Пошти».

Javascript зберігає об'єкт в пам'яті до тих пір, поки на нього є хоч одне посилання. Як тільки ви видаляєте всі посилання на об'єкт, він знищується збирачем сміття.

Щоб видалити об'єкт, потрібно видалити всі посилання на нього.

Це здається дуже простим, але є кілька досить несподіваних «місць» де можуть зберігатися посилання на об'єкти, тим самим затримуючи їх видалення, і створюючи витік пам'яті.

1. Консольний висновок.

Якщо в процесі роботи програми в консоль виводиться зневаджувальна інформація, то перш ніж заміряти пам'ять, консоль варто очистити.

Це не обов'язково призведе до зменшення споживання пам'яті, але на своїй практиці я вже зустрічався з випадками, коли очищення консолі звільняло об'єкти з пам'яті.

2. Увімкнені експериментальні функції переглядача.

У моєму випадку це були «JavaScript frameworks debugging» і «Support asynchronous call stacks», яка вже вийшла з експериментальних.

До тих пір, поки вони були включені, частина об'єктів в пам'яті не видалялося збирачем сміття, хоча в самому додатку посилань на них не було.

Коли я зняв галочки, проблеми зникли.

До речі, в додатку, який я розробляю, рендеряться складні шаблони на AngularJS, і з увімкненими експериментальними функціями рендер тривав близько 10 секунд, а з відключеними - всього 3.

Як справи йдуть з іншими експериментальними функціями, сказати не можу, але раджу на час пошуку витоків пам'яті все відключати.

3. Розширення переглядача.

У моєму випадку це був Batarang. Це інструмент для зневаджування програм, побудованих на AngularJS, і він у себе всередині зберігає посилання на scope програми, що створювало витік пам'яті.

Після того, як я відключив розширення, пам'ять стала звільнятися.

Плагінів, що впливають на роботу з пам'яттю може бути безліч. За посиланням, яке я дав на початку статті, рекомендується відключати взагалі всі плагіни, що, як я вважаю, є правильною порадою.

4. Функція «Record Heap Allocations».

Ця функція потрібна для того, щоб визначити, в який момент скільки пам'яті відкладається додатком, і що конкретно в який момент відкладається. Це дуже корисна річ, але в роботі цієї функції є деякі особливості.

Перше - функція показує не тільки скільки пам'яті відкладається, але і скільки звільняється («вільна» пам'ять стає світло-сірою), при цьому показувати може не завжди точно.

Для того, щоб зрозуміти, в який момент скільки пам'яті використовується, варто використовувати Timeline.

Для тесту я повторював багато разів одну дію в додатку, і дивився, що відбувається з пам'яттю.

Record Heap Allocations показував, що пам'ять очищалася не повністю, і після кожної дії залишалося трохи зайнятої пам'яті, в той час, як Timeline показував, що все очищається добре, і ніяких витоків немає.

Друге - не варто використовувати Record Heap Allocations і Timeline одночасно.

Якщо одночасно включити Record Heap Allocations і Timeline, то Timeline буде показувати, що пам'ять тече, тобто використовується у все більшому і більшому обсязі.

Якщо ж включити один тільки Timeline, то пам'ять текти не буде, що призводить до висновку, що Record Heap Allocations утримує посилання на об'єкти, а тому непридатний для відстеження «звільнення» пам'яті.

Ув'язнення

У статті я навів 4 приклади місць, де можуть бути збережені посилання на об'єкти, що перешкоджають їх видаленню збирачем сміття.

Природно, це не всі проблемні місця, а лише тільки ті, з якими зіткнувся особисто я.

Щось із цього, можливо, вже виправлено, а щось, можливо, буде виправлено в майбутньому.

Важливо розуміти, що крім найбільш розроблюваного програми посилання можуть бути збережені і в інших місцях, і це слід враховувати при пошуку витоків пам'яті.