Ионная 4.2.1 Модальная утечка памяти - PullRequest
0 голосов
/ 06 ноября 2018

Я разрабатываю приложение для киоска с Ionic для использования на 12,9 "iPad Pro. После их запуска в течение нескольких недель я заметил снижение производительности анимации (особенно с элементом <ion-slides>) и проследил ее из-за утечки памяти. В этом приложении я использую два модальных режима. Когда какой-либо модальный режим отклонен, если я принудительно собираю мусор, то просматриваю временную шкалу выделения памяти и снимки памяти в инструментах разработчика Chrome. Элементы DOM. Каждый раз, когда модал закрывается и открывается заново, выделенная память становится чуть-чуть больше. Один из этих модалей довольно сложный с динамическим элементом src <video> и соответствующими кнопками управления воспроизведением, а другой довольно простой, состоящий из только несколько текстовых элементов, извлеченных из данных json с использованием * ngFor.

Обычно эта утечка памяти не будет достаточно большой, чтобы о ней беспокоиться. Ваш обычный пользователь никогда не будет открывать и закрывать модалы настолько, чтобы вызвать проблемы в разумные сроки. Но эти iPad находятся в публичном пространстве и каждый день получают сотни пользователей только этого приложения. В зависимости от того, насколько мы заняты, требуется около недели использования, прежде чем утечки памяти вызовут заметные проблемы. Они работают в режиме одного приложения. Таким образом, чтобы перезапустить их, мне нужно разблокировать корпус киоска, извлечь iPad, подключить их к Конфигуратору на моем компьютере, перезапустить и заново установить их в корпус. Не совсем то, чем я хочу заниматься каждые несколько дней, если я могу избежать этого.

Я нашел несколько других постов, здесь и на GitHub, по аналогичным вопросам, но ни одного с реальными ответами. Есть ли способ убедиться, что эти модалы должным образом уничтожены, когда они уволены?

Ionic - не моя типичная платформа для разработки. Обычно я работаю в React, но кто-то решил, что мы должны использовать iPad для этого, несмотря на то, что все мы говорили им, что это ужасная идея. Так что вполне возможно, что я идиот, и здесь есть что-то очевидное, чего мне не хватает.

Спасибо!

Код для более простого кода ...

JS

import { Component } from '@angular/core';
import { NavController, NavParams, Events, ViewController } from 'ionic-angular';
import { CreditsProvider } from '../../providers/credits/credits';

/**
 * Generated class for the CreditsModalPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@Component({
  selector: 'page-credits-modal',
  templateUrl: 'credits-modal.html',
})
export class CreditsModalPage {
  public games = [];
  public ahStaff = [];
  public playCapture = [];

  constructor(private creditsProvider: CreditsProvider, public navCtrl: NavController, public navParams: NavParams, public events: Events, private viewCtrl: ViewController) {
    events.subscribe('timeout', (state) => {
      if (state === 'home') {
        this.viewCtrl.dismiss();
      }
    })
  }

  ionViewDidLoad() {
    this.creditsProvider.getCredits().subscribe((response) => {
      this.games = response.games;
      this.ahStaff = response.ahStaff;
      this.playCapture = response.playCapture;

      //update all staff to not show easter egg
      this.ahStaff.forEach(staff => {
        staff.showNickname = false;
      });
    });
  }

  /*
  * If the staff member has a nickname, toggle the easter egg on and off
  */
  toggleEasterEgg(index) {
    if(this.ahStaff[index].nickname !== null){//if they have a nickname
      //toggle the easter egg
      this.ahStaff[index].showNickname = !this.ahStaff[index].showNickname;
    }
  }
}

HTML

<!--
  Generated template for the CreditsModalPage page.

  See http://ionicframework.com/docs/components/#navigation for more info on
  Ionic pages and navigation.
-->
<ion-header>

  <ion-navbar color="dark">
    <ion-title>Credits</ion-title>
  </ion-navbar>

</ion-header>


<ion-content padding class="creditsContent">
  <h1>Staff</h1>
  <div class="credit" *ngFor="let staff of ahStaff; let i = index">
    <p (click)="toggleEasterEgg(i)" >{{staff.role + ' - '}}<span [ngClass]="{'glitch': staff.showNickname}" [attr.data-text]="staff.nickname">{{staff.showNickname ? staff.nickname : staff.name}}</span></p>
  </div>
  <h1>Play Capture</h1>
  <div class="credit" *ngFor="let player of playCapture">
    <p>{{player}}</p>
  </div>
  <h1>Games</h1>
  <div class="credit" *ngFor="let game of games">
    <h2>{{game.name}}</h2>
    <p *ngIf="game.year !== null">{{"Year Published - " + game.year}}</p>
    <p *ngIf="game.developer !== null">{{"Developer - " + game.developer}}</p>
    <p *ngIf="game.publisher !== null">{{"Publisher - " + game.publisher}}</p>
    <p *ngIf="game.note !== null">{{game.note}}</p>
  </div>

</ion-content>

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Спасибо за помощь @Gilsdav. Но, похоже, это проблема самого Ionic. Я сделал то, что должен был сделать вначале, и сразу перешел к документации Ionic Modal здесь и искал утечки памяти на примере, который там есть. Конечно же, я вижу точно такое же поведение. Временная шкала производительности Ionic Docs . Слушатели, JS Heap и Documents очищаются при сборке мусора, но DOM-узлы продолжают расти. Глядя на снимки кучи, я вижу все содержимое модала в виде отдельных элементов DOM, точно так же, как я делал это со своим собственным кодом.

В 99% случаев использования эта утечка достаточно мала, и это не будет большой проблемой. Так что я бы не стал считать это огромной проблемой с Ionic. Но мне нужно, чтобы это можно было проводить месяцами без проблем. Так что, похоже, я либо найду способ переформатировать это, чтобы не использовать модалы, либо мне придется искать способ перезагрузить iPad ночью.

Обновление !!!

Так что, если кому-то еще понадобится решение этой проблемы, вот что я в итоге сделал. Я не уверен, что это правильный путь, но, похоже, он работает.

Одним из модальных проблем было сообщение о тайм-ауте, которое просто периодически проверяет, что кто-то еще там. Если никто не отвечает, он просто сбрасывает приложение на основной экран. Когда этот модал закрыт, я просто позвонил window.location.reload(), чтобы перезагрузить приложение. Это определенно не выглядит красиво при тестировании в Chrome, но на самом деле довольно легко при работе на устройстве.

Глядя на распределение javascript на реальном устройстве, с помощью Safari Developer Tools, я вижу, что размер живого изображения постоянно увеличивается, когда я открываю и закрываю модалы. Но, как только этот тайм-модальный режим исчезает и перезагружается, он возвращается к исходному уровню.

0 голосов
/ 07 ноября 2018

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

private onTimeout = (state) => {
    if (state === 'home') {
      this.viewCtrl.dismiss();
    };
}

ionViewDidLoad() {
    this.events.subscribe('timeout', onTimeout);
}

ionViewWillLeave() {
    this.events.unsubscribe('timeout', onTimeout);
}
...