Чому сторінка Safari порушує візуалізацію iOS?


79

Я знаю, що назва не така пояснювальна, але ось історія: я розробляю браузерну гру, переважно використовуючи JavaScript та бібліотеку Mapbox.

Все працює добре на настільних комп’ютерах, Android та iOS, але на iOS з’являється одна проблема: після запуску гри протягом декількох хвилин телефон раптово починає мати графічні артефакти та відображати більшу частину тексту.

Ось кілька фотографій того, як теж виглядає телефон: введіть тут опис зображення введіть тут опис зображення введіть тут опис зображення

Моє запитання : що саме в моєму коді може спричинити це? Витік пам'яті? ( LE : це виявилося насправді витоком пам'яті)
Справжнє запитання : як це виходить, що ви можете майже змурувати весь телефон, просто переглядаючи веб-сторінку? Чи не повинен Safari зупинити це чи, принаймні, iOS?

Це не проблема з цим конкретним пристроєм, оскільки ця проблема може бути відтворена на різних пристроях iPhone. (Я не настільки впевнений у різних версіях iOS).

Як я можу відтворити помилку:

  1. Відкрийте гру (всередині Safari).
  2. Нехай працює 3-4 хвилини.
  3. Посуньте вниз центр сповіщень, і все збожеволіє.
    Я додав відео на YouTube, де показано, як я можу відтворити помилку (на моєму iPhone 5C).
    Здається, проблема вперше з’являється в центрі сповіщень (якщо провести пальцем вниз по меню зверху).
    Наразі ця проблема, схоже, виникає лише в iPhone 5CiOS 9.2.1 (13D15). Це також відбувається в новій версії iOS 9.3.

Для того, щоб вирішити цю проблему, я повинен:

  1. Закрийте програму Safari (у якій відкрита вкладка гри).
  2. Заблокуйте телефон. Після розблокування все нормалізується.

Деякі подробиці про саму гру :

  1. У грі показана карта Mapbox та деякі одиниці над нею (маркери).
  2. Сервер Node.js працює зі швидкістю 1 тик / с, і після кожного тику оновлений стан гри надсилається у браузер через Socket.io.
  3. Щоразу, коли браузер отримує стан гри, він відповідно оновлює маркери.
  4. * Гра також може оновлювати маркери, якщо ви збільшуєте або зменшуєте масштаб або ви вибираєте їх.

EDIT2: виявлено витік пам’яті (як очікувалося). Після виправлення цього витоку (перевірте наявність undefined_icon) проблема більше не виникає. Це означає, що десь уздовж цих ліній запускається помилка Safari / iOS.

Ось як саме називали кожну галочку для кожної одиниці, яка була згрупована (була прихована та згрупована з іншими всередині MarkerCluster):

    var $icon = $(marker._icon); // marker._icon is undefined because of the clustering

    $icon.html('');

    $icon.append($('<img class="markerIcon" src="' + options.iconUrl + '" />'));

    var iconX = 10;
    var iconY = -10;
    var iconOffset = 0;

    for(var v in this.icons) {
        this.icons[v].css('z-index', + $icon.css('z-index') + 1);
        this.icons[v].css('transform', 'translate3d(' + iconX + 'px,' 
                                + (iconY + iconOffset) + 'px,' + '0px)');
        iconOffset += 20;

        this.icons[v].appendTo($icon);
    }

    // Fire rate icons
    this.attackRateCircle = $('<div class="circle"></div>');
    this.attackRateCircle.circleProgress({
        value: 0,
        size: 16,
        fill: { color: "#b5deff" },
        emptyFill: 'rgba(0, 0, 0, 0.5)',
        startAngle:  -Math.PI / 2,
        thickness: 4,
        animation: false,
    });
    this.attackRateCircle.hide();

    // Create and display the healthbar
    this.healthBar = $('<div>').addClass('healthBar ');
    this.healthBar.css('z-index', $icon.css('z-index'));
    this.healthBarFill = $('<span class="fill">');
    this.healthBar.append(this.healthBarFill);

    $icon.append(this.healthBar);
    $icon.append(this.attackRateCircle);

І це iconsмасив:

this.icons = {
    attack_order: $('<img src="img/attack.png" class="status_icon">'),
    attack: $('<img src="img/damage.png" class="status_icon icon_damage">'),
    hit: $('<img src="img/hit.png" class="status_icon icon_hit">'),
};

circleProgressдзвінок з цієї бібліотеки: https://github.com/kottenator/jquery-circle-progress

ДЕМО

Так, я зміг створити jsFiddle, який відтворює помилку: https://jsfiddle.net/cte55cz7/14/ Відкрити в Safari на iPhone 5C і зачекати пару хвилин. На iPhone 6 і iPad mini сторінка виходить з ладу (як очікувалося через витік пам'яті)

Ось той самий код у HasteBin для тих, хто не хоче його запускати.


2
PS: Опубліковано на SO після того, як його проголосували за розміщення запитання на SuperUser. Я сподіваюся, що це вважається правильним місцем для того, щоб поставити це питання.
XCS

2
@wottle Я тестував на своєму iPhone 5C, а інша людина тестувала (на іншому континенті: D) на іншому iPhone, але я думаю, що його модель теж 5C (і саме він насправді розповів мені про ці артефакти). Завтра я тестуватиму на iPhone 6 та iPad mini.
XCS

2
Не відтворюється на моєму iPhone 6. Це може бути помилка в CG. Чи можете ви розмістити всю інформацію про версію iOS разом із інформацією про обладнання?
Fresheyeball

2
Оце Так! І я думав, що розрив екрану на Windows 10 Mobile був поганим ...
BoltClock

6
А) Я навіть не злюся. Це дивовижно. Б) Я напевно замислююсь, чи насправді це можна використовувати як експлойт, оскільки ти чітко отримуєш доступ до пам’яті, до якої ти не міг би мати змогу, і В) Я думаю, що цікаво, що все завжди нахиляється вліво. Мені це підказує, що з якихось причин ви збільшуєте або висоту тонусу (тобто кроки) деяких текстур, або модифікуєте логіку кроку графічного процесора. Безумовно, помилка Safari / iOS / прошивки.
0x24a537r9,

Відповіді:


1

Цей витік пам'яті, ймовірно, пов'язаний з тим, як працює "механізм JS WebKit" [safari webkit-javascript llvm]

і справді виглядає як переповнення буфера віртуальної пам’яті, що має прямий вплив на решту оперативної пам’яті (спільна та використовується також iOS для зберігання графічних елементів інтерфейсу користувача)

Щодо шматка коду: "[...] знайти витоки пам'яті jQuery легко. Перевірте розмір $ .cache. Якщо він занадто великий, огляньте його і подивіться, які записи залишаються і чому. [...]" ( http://javascript.info/tutorial/memory-leaks )

Дозвольте мені очікувати, що це відносно цього циклу for :

for(var v in this.icons) {
    this.icons[v].css('z-index', + $icon.css('z-index') + 1);
    this.icons[v].css('transform', 'translate3d(' + iconX + 'px,' 
                            + (iconY + iconOffset) + 'px,' + '0px)');
    iconOffset += 20;

    this.icons[v].appendTo($icon);
}

Припускаючи, що перевірку зроблено, а також припускаючи той факт, що ви знайдете записи, можливо, ви захочете очистити дані вручну за допомогою removeData () або ви можете спочатку використовувати $ elem.detach (), а потім поставити $ (elem) .remove () у setTimeout.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.