Tại sao trang Safari phá vỡ kết xuất iOS?


79

Tôi biết tiêu đề không phải là giải thích nhưng đây là câu chuyện: Tôi đang phát triển một trò chơi trình duyệt, chủ yếu sử dụng JavaScript và thư viện Mapbox.

Mọi thứ hoạt động tốt trên máy tính để bàn, Android và iOS nhưng một vấn đề xuất hiện trên iOS: sau khi để trò chơi chạy trong vài phút, điện thoại đột nhiên bắt đầu có hiện tượng đồ họa và hiển thị phần lớn văn bản bị xáo trộn.

Dưới đây là một số hình ảnh về những gì điện thoại bắt đầu trông giống như: nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Câu hỏi của tôi là: chính xác thì điều gì trong mã của tôi có thể gây ra điều này? Một bộ nhớ bị rò rỉ? ( LE : hóa ra thực sự là một sự cố rò rỉ bộ nhớ)
Câu hỏi thực sự là: Làm thế nào mà bạn có thể gần như đóng toàn bộ điện thoại chỉ bằng cách duyệt một trang web? Safari không nên dừng điều này hay ít nhất là iOS?

Đây không phải là vấn đề với thiết bị cụ thể này, vì vấn đề này có thể được tái tạo trên các thiết bị iPhone khác nhau. (Tôi không chắc lắm về các phiên bản iOS khác nhau).

Cách tôi có thể tạo lại lỗi:

  1. Mở trò chơi (bên trong Safari).
  2. Để nó chạy trong 3-4 phút.
  3. Trượt xuống trung tâm thông báo và mọi thứ trở nên điên rồ.
    Tôi đã thêm một video YouTube cho biết cách tôi có thể tái tạo lỗi (trên iPhone 5C của tôi).
    Có vẻ như sự cố xuất hiện đầu tiên trong trung tâm thông báo (nếu bạn vuốt menu từ trên xuống).
    Hiện tại, sự cố này dường như chỉ xảy ra trên iPhone 5CiOS 9.2.1 (13D15). Nó cũng xảy ra trên phiên bản iOS 9.3 mới.

Để khắc phục sự cố này, tôi phải:

  1. Đóng ứng dụng Safari (trong đó tab trò chơi đang mở).
  2. Khóa điện thoại. Sau khi mở khóa, mọi thứ trở lại bình thường.

Một số thông tin chi tiết về trò chơi :

  1. Trò chơi hiển thị một bản đồ Mapbox và một số đơn vị trên đó (điểm đánh dấu).
  2. Máy chủ Node.js chạy với tốc độ 1 lần đánh dấu / giây và sau mỗi lần đánh dấu, trạng thái trò chơi được cập nhật sẽ được gửi đến trình duyệt thông qua Socket.io.
  3. Mỗi khi trình duyệt nhận được trạng thái trò chơi, nó sẽ cập nhật các điểm đánh dấu tương ứng.
  4. * Trò chơi cũng có thể cập nhật các điểm đánh dấu nếu bạn phóng to hoặc thu nhỏ hoặc nếu bạn chọn chúng.

EDIT2: Tìm thấy rò rỉ bộ nhớ (như mong đợi). Sau khi sửa lỗi rò rỉ này (kiểm tra undefined_icon), sự cố không còn xảy ra nữa. Điều này có nghĩa là ở đâu đó dọc theo những dòng đó, lỗi Safari / iOS được kích hoạt.

Đây là những gì chính xác được gọi là mỗi dấu kiểm, cho mỗi đơn vị đã được nhóm (được ẩn và nhóm với những người khác bên trong 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);

Và đây là iconsmảng:

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">'),
};

circleProgresscuộc gọi đến từ thư viện này: https://github.com/kottenator/jquery-circle-progress

BẢN GIỚI THIỆU

Vâng, tôi đã có thể tạo jsFiddle tái tạo lỗi: https://jsfiddle.net/cte55cz7/14/ Mở trên Safari trên iPhone 5C và đợi vài phút. Trên iPhone 6 và iPad mini, trang bị treo (như mong đợi do rò rỉ bộ nhớ)

Đây là mã tương tự trong HasteBin, dành cho bất kỳ ai không muốn chạy nó.


2
PS: Được đăng trên SO sau khi bị phản đối vì đã đăng câu hỏi trên SuperUser. Tôi hy vọng rằng đây được coi là nơi thích hợp để đặt câu hỏi này.
XCS

2
@wottle Tôi đã thử nghiệm trên iPhone 5C của mình và một người khác đã thử nghiệm (ở lục địa khác: D) trên iPhone khác, nhưng tôi nghĩ rằng mẫu của anh ấy cũng là 5C (và anh ấy là người thực sự nói với tôi về những hiện vật đó). Tôi sẽ thử nghiệm trên iPhone 6 và iPad mini vào ngày mai.
XCS

2
Không tái tạo trên iPhone của tôi 6. Nó có thể là một lỗi trong CG. Bạn có thể đăng tất cả thông tin phiên bản ios cùng với thông tin phần cứng không?
Fresheyeball

2
Chà! Và tôi nghĩ rằng màn hình bị rách trên Windows 10 Mobile là do ...
BoltClock

6
A) Tôi thậm chí không điên. Thật đáng kinh ngạc. B) Tôi hơi thắc mắc liệu điều này có thực sự được sử dụng như một cách khai thác hay không, vì rõ ràng bạn đang truy cập bộ nhớ mà bạn không thể làm được, và C) Tôi nghĩ thật thú vị khi mọi thứ luôn nghiêng về bên trái. Điều đó gợi ý cho tôi rằng vì lý do nào đó, bạn đang tăng cường độ (hay còn gọi là bước tiến) của một số kết cấu hoặc sửa đổi logic cao độ của GPU. Chắc chắn là lỗi Safari / iOS / firmware.
0x24a537r9 Ngày

Câu trả lời:


1

Bộ nhớ này bị rò rỉ có thể là do cách hoạt động của 'WebKit's JS Engine' [safari webkit-javascript llvm]

và thực sự trông giống như một sự cố tràn bộ nhớ ảo, có tác động trực tiếp đến RAM còn lại (được chia sẻ và sử dụng bởi iOS để lưu trữ các thành phần đồ họa Giao diện người dùng)

Tương đối với đoạn mã: "[...] việc tìm kiếm rò rỉ bộ nhớ jQuery rất dễ dàng. Kiểm tra kích thước của $ .cache. Nếu nó quá lớn, hãy kiểm tra nó và xem mục nào ở lại và tại sao. [...]" ( http://javascript.info/tutorial/memory-leaks )

Hãy để tôi mong đợi rằng nó liên quan đến vòng lặp for này :

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);
}

Giả sử việc kiểm tra đã hoàn tất và cũng giả sử thực tế là bạn tìm thấy các mục nhập, bạn có thể muốn xóa dữ liệu theo cách thủ công với removeData () hoặc bạn có thể sử dụng $ elem.detach () trước tiên và sau đó đặt $ (elem) .remove () trong setTimeout.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.