12/08/2018, 14:11

Phát hiện các vấn đề về memory trong phát triển ứng dụng iOS

Một app tốt không chỉ chạy đúng mà còn phải chạy nhanh, tiêu tốn ít tài nguyên nhất có thể. Trong quá trình làm dự án, có nhiều lý do dẫn đến tồn tại nhiều vấn đề về memory có thể không ảnh hưởng tại thời điểm hiện tại, nhưng nó tiềm ẩn gây ra vấn đề sau này. Trong bài này, mình xin giới thiệu một ...

Một app tốt không chỉ chạy đúng mà còn phải chạy nhanh, tiêu tốn ít tài nguyên nhất có thể. Trong quá trình làm dự án, có nhiều lý do dẫn đến tồn tại nhiều vấn đề về memory có thể không ảnh hưởng tại thời điểm hiện tại, nhưng nó tiềm ẩn gây ra vấn đề sau này. Trong bài này, mình xin giới thiệu một số vấn đề về memory có thể gặp phải khi phát triển ứng dụng iOS và cách để phát hiện ra các vấn đề này.

Trong khuôn khổ bài này, mình xin đưa ra 2 vấn đề và cách phát hiện

  • Abandoned Memory
  • Leaks Memory

Abandoned Memory là gì

Trích nguyên văn Apple Doc:

“Abandoned memory is memory that you allocated for some reason but simply don’t need anymore”.

Abandoned memory là vùng nhớ được cấp phát để lưu thông tin nào đó, nhưng sau đó thông tin đã lưu không còn cần thiết/được sử dụng nữa, vùng nhớ vẫn còn tồn tại, vẫn có thể access bình thường.

Abandoned memory xảy ra khi bộ nhớ không ngừng tăng lên khi thực hiện lặp đi lặp lại cùng một chuỗi các thao tác.

Để dễ hiểu, mình lấy ví dụ đơn giản và có thể khác một chút so với thực tế.

Ví dụ khi chuyển từ view controller A sang view controller B, tại view controller B, một số object được khởi tạo và cache lại. Khi quay lại view controller A thì các object không còn cần thiết nữa thì cần clear cache đi. Tuy nhiên nếu không thực hiện việc clear cache, khi thực hiện lặp đi lặp lại các thao tác: view controller A -> view controller B -> view controller A, bộ nhớ sẽ liên tục tăng lên. Các object nằm trong Cache, ta vẫn có thể acccess được, tuy nhiên nó không còn được sử dụng nữa.

Công cụ: Allocation Template Instrument

Allocation template quét thông tin vùng heap memory và track lại thông tin các allocations.

Flow chung:

  1. Từ trạng thái ban đầu track lại thông tin allocations
  2. Thực hiện một số thao tác
  3. Quay trở về trạng thái ban đầu và track lại thông tin allocations một lần nữa

Thực hiện kiểm tra xem heap memory tiếp tục tăng lên hay giảm xuống như trạng thái ban đầu.

Chú ý để việc kiểm tra dễ dàng và chính xác hơn:

  • Cần thực hiện lặp lại các thao tác trên một vài lần.
  • Heap memory có thể tăng lên do một số system library, cần kiểm tra xem việc cấp phát được thực hiện bởi code của mình.
  • Công cụ này chỉ giúp track lại các allocations, phần việc còn lại để tìm ra memory issue là ta thực hiện, do số lượng allocations hơi nhiều nên cần kiên nhẫn xí

Các bước sử dụng Allocation template

  1. Xcode Open Developer Tool Instrutments
  2. Chọn Allocations template

Picture1.png

  1. Chọn app cần kiểm tra từ Choose target pop-up menu. Ví dụ ở đây là AbandonedMemoryDemo app

  2. Ấn nút Record (nút tròn màu đỏ) để bắt đầu

  3. Thực hiện các thao tác trên app theo flow chung đã nói ở phần trước. Để thực hiện ghi lại thông tin các allocations nhấn nút Generation

Picture1.png

Trong từng Generation, tìm kiếm object có thể được allocate, với mỗi đối tượng chọn instance nào đó.

Ví dụ: đối tượng NSDate, có instance 0x7fa2ebf018e0

Picture1.png

  • Click Extended Detail ở inspector sidebar. Dòng nào mà có ô vuông đen có hình người dùng thì đó là code của chúng ta đã khởi tạo đối tượng mà ta đang xem xét
  • Click vào dòng đó để xem code

Picture1.png

  • Click Xcode icon để xem code bằng Xcode

Leaks Memory là gì

Theo Apple Docs:

Memory leaks are blocks of allocated memory that the program no longer references

Leaks memory là vùng nhớ chưa được release nhưng không còn và không thể access được nữa.

Với việc quản lý bộ nhớ bằng tay (Manual Memory Management), khi khởi tạo một object bằng alloc, thì khi không còn dùng object đó nữa ta phải dùng release để object đó có thể bị huỷ đi, không còn chiếm bộ nhớ nữa.

Sau này, khi ARC (Automatic Reference Counting) ra đời, các lệnh như alloc, release được complier tự động thêm vào. Tuy nhiên leaks memory vẫn có thể xảy ra do retain cycle.

Retain cycle là khi 2 object giữ strong reference đến nhau, ngăn cản việc release của nhau.

Một ví dụ về memory leaks do retain cycle:

  • Đối tượng Person có thuộc tính name và apartment người đó ở.
  • Đối tượng Appartment có thuộc tính name và person ở trong appartment đó.
var john: Person? = Person(name: John Appleseed)
var number73: Appartment? = Appartment(number: 73)
john?.apartment = number73
number73?.tenant = john

Screen Shot 2016-11-22 at 9.28.49 AM.png

Khi huỷ references giữ bởi john và number73

john = nil
number73 = nil

Person instance và Appartment instance vẫn không thể deallocate được do chúng giữ strong reference đến nhau. Vùng nhớ do 2 instance này chiếm giữ không được release, cũng không access được. Điều này gây ra leaks memory.

Screen Shot 2016-11-22 at 9.28.54 AM.png

Công cụ: Leaks Template Instrument

  1. Xcode -> Open Developer Tool -> Instrutments
  2. Chọn Leaks template
  3. Chọn target
  4. Click Record button
  5. Thao tác trên app, khi có đường màu đỏ xuất hiện, nghĩa là có leaks, click stop để dừng

Picture1.png

  1. Chọn đối tượng bị leaks, ở Extended Detail inspector, click vào stack trace instruction để xem code gây ra leaks

Picture1.png

  1. Click vào hình mũi tên sau mỗi instance để xem quá trình tăng giảm “retain count”

Picture1.png

  1. Dựa vào quá trình tăng giảm retain count mà tìm ra nguyên nhân gây ra leaks

Picture1.png

Với ví dụ, nguyên nhân như sau:

  1. Department *number73 = [[Department alloc] init]: retain count = 1 (malloc)
  2. john.department = number73: retain count = 2 (retain)
  3. number73 = nil (tự động bởi ARC khi ra khỏi variable scrope): retain count = 1 (release)

Vùng nhớ mà number73 trỏ đến không thể được release vì retain giữ nguyên là 1, không thể giảm về 0. Điều này gây leaks memory.

Trên đây mình vừa trình bày 2 vấn đề memory thường mắc phải trong phát triển ứng dụng iOS và cách phát hiện ra chúng.

Để thuận tiện trong việc chuyển tải nội dung bài viết, giúp các bạn nắm bắt được phương pháp, các ví dụ mình sử dụng rất đơn giản. Trong thực tế dự án, các vấn đề thường phức tạp hơn và tốn nhiều effort để tìm ra vấn đề. Tuy nhiên, năm được phương pháp và kiên nhẫn một chút, chắc chắn sẽ tìm ra được vấn đề.

Hi vọng bài viết sẽ giúp ích được gì đó.

0