Memory Graph: ano ito, graph ng mga bagay at pagtuklas ng mga siklikal na sanggunian

May-akda: IT Sectr Nai-publish: 2026-05-07 Oras ng pagbabasa: 10 min

Memory Graph — ang biswal na kasangkapan ng Xcode Debug Navigator na nagpapakita ng graph ng mga bagay sa RAM ng application kasama ang kanilang mga mutual na sanggunian. Hindi tulad ng heap dump, ang Memory Graph ay nagpapakita hindi lamang ng listahan ng mga bagay, kundi isang nakadirektang graph ng mga sanggunian, kung saan ang bawat node ay isang bagay at ang bawat gilid ay isang sanggunian (strong, weak, unowned). Ayon sa Apple WWDC 2018, ang kasangkapan ay nagbibigay-daan sa biswal na pagtuklas ng retain cycles at mga tagas ng memorya sa loob ng ilang segundo, nang walang pangangailangan na suriin ang raw data ng heap dump.

Mga Pangunahing Punto

  • Memory Graph — biswal na graph ng mga bagay sa memorya ng Xcode, nagpapakita ng mga sanggunian sa pagitan ng mga bagay sa real-time.
  • Retain cycle ay natutuklasan sa pamamagitan ng saradong contour sa graph — dalawa o higit pang mga bagay ang tumutukoy sa isa't isa gamit ang malalakas na sanggunian.
  • Backtrace para sa bawat gilid ng graph ay nagpapakita kung saan at kailan itinatag ang sanggunian, pinapadali ang paghahanap ng pinagmulan ng tagas.
  • Pagsala ayon sa pangalan ng klase at uri ng sanggunian (strong/weak) ay nagbibigay-daan sa mabilis na paghiwalay ng mga problematikong bagay.
  • Integrasyon sa Memory Report sa Xcode ay nagbibigay-daan sa pagsubaybay ng pagbabago sa konsumo ng memorya sa real-time.

Ano ang Memory Graph at paano ito gumagana

Memory Graph — ay isang bahagi ng Xcode Debug Navigator (lumitaw sa Xcode 10, WWDC 2018) na bumubuo ng nakadirektang graph ng lahat ng bagay sa memorya ng prosesong dini-debug. Ang bawat node ng graph ay isang instance ng klase (Objective-C o Swift), ang bawat gilid ay isang sanggunian sa ibang bagay. Ang kulay ng gilid ay nagpapahiwatig ng uri ng sanggunian: asul — strong, berde — weak, kulay-abo — unowned. Ang graph ay binuo batay sa data ng LLDB at Objective-C runtime, kaya naman para sa tamang paggana ang application ay dapat na compile sa Debug configuration na may naka-enable na mga simbolo.

Prinsipyo ng paggana: kapag ang application ay naka-pause sa breakpoint, ang Xcode sa pamamagitan ng LLDB ay humihiling sa runtime ng lahat ng buhay na bagay at kanilang mga sanggunian. Ginagamit ng LLDB ang objc_getClassList at pag-ulit sa mga rehiyon ng alokasyon para sa pagbuo ng kumpletong graph. Sa ARM64 (Apple Silicon) karagdagang ginagamit ang mga hardware na paraan para sa pagsubaybay ng alokasyon nang walang pagbagal. Ang oras ng pagbuo ng graph ay depende sa laki ng heap: para sa tipikal na iOS application (50–200 MB) ang graph ay binuo sa loob ng 1–3 segundo.

Ayon sa Apple, ang Memory Graph ay ang tanging kasangkapan na maaaring mag-visualize ng retain cycles nang walang pagbabago ng code o pagdaragdag ng instrumentasyon. Hindi tulad ng Instruments Leaks, ang Memory Graph ay gumagana sa real-time sa loob ng Xcode at hindi nangangailangan ng hiwalay na paglunsad ng profiler. Ginagawa nitong unang pagpipilian na kasangkapan para sa mabilis na diagnosis ng mga tagas ng memorya sa proseso ng pag-develop.

Pagkakaiba ng Memory Graph sa heap dump

Heap dump ay nagbibigay ng talahanayan ng lahat ng bagay na may mga numero (shallow size, retained size) — ito ay optimal para sa kwantitatibong pagsusuri. Memory Graph ay nagbibigay ng biswal na larawan ng mga koneksyon — ito ay optimal para sa paghahanap ng mga siklikal na sanggunian. Ang mga kasangkapan ay nagpupuno sa isa't isa: una Memory Graph para sa mabilis na pagtuklas ng retain cycles, pagkatapos heap dump sa pamamagitan ng Instruments Allocations para sa tumpak na pagsukat ng retained size. Ayon sa karanasan ng objc.io, ang kombinasyon ng dalawang pamamaraan ay sumasaklaw sa 95% ng mga senaryo ng tagas ng memorya.

Pagtuklas ng retain cycles gamit ang Memory Graph

Retain cycle — sitwasyon kung saan ang dalawa o higit pang mga bagay ay nagpapanatili sa isa't isa gamit ang malalakas na sanggunian, na bumubuo ng isang saradong contour. Hindi maaaring pakawalan ng ARC ang naturang contour dahil ang retain count ng bawat bagay ay hindi kailanman umaabot sa zero. Klasikong halimbawa: ViewController at View, kung saan ang View ay may strong reference sa closure na kumukuha ng self (ViewController). Ang Memory Graph ay nagpapakita ng mga naturang contour sa anyo ng mga singsing (siklo), na nagha-highlight sa mga ito para sa mabilis na identipikasyon.

Kapag nakita ng Xcode ang isang retain cycle, iha-highlight nito ito ng orange na contour at magpapakita ng babala sa Debug Navigator. Sa pag-click sa siklo, makikita mo ang kadena ng mga sanggunian na bumubuo ng saradong contour. Ang natitira na lang sa developer ay alamin kung aling malakas na gilid ang dapat maging mahina — karaniwan ito ang sanggunian mula sa anak na bagay patungo sa magulang (hal., delegate o closure).

swift
class ViewController: UIViewController {
    let service = DataService()

    override func viewDidLoad() {
        super.viewDidLoad()
        // ❌ Siklo ng retain: ViewController → serbisyo → closure → ViewController
        service.fetchData { self.updateUI($0) }
    }

    func updateUI(_ data: Data) {}
}

class DataService {
    var completion: ((Data) -> Void)?

    func fetchData(handler: @escaping (Data) -> Void) {
        self.completion = handler
    }
}

Sa Memory Graph makikita mo ang isang tatsulok: ViewController → DataService → closure → ViewController. Ang solusyon — mahinang pagkuha ng self: [weak self]. Pagkatapos ng pagwawasto, ang Memory Graph ay magpapakita ng berdeng gilid mula closure patungo sa ViewController, at mawawala ang retain cycle.

swift
// Itinamang code — mahinang pagkuha ng self
service.fetchData { [weak self] data in
    guard let self else { return }
    self.updateUI(data)
}

Interface ng Memory Graph Debugger sa Xcode

Ang interface ng Memory Graph Debugger ay binubuo ng tatlong panel: kaliwa — listahan ng lahat ng buhay na bagay (pinangkat ayon sa klase) na may bilang ng mga instance; gitna — biswal na graph na may mga node na maaaring i-drag; kanan — inspektor ng napiling bagay o gilid. Sa listahan ng mga bagay ay ipinapakita: icon ng klase, bilang ng mga instance sa memorya, kabuuang retained size at porsyento ng buong heap. Ang pagsala ayon sa pangalan ng klase ay sumusuporta sa mga regular na expression.

Pag-navigate sa graph

Ang mga node ng graph ay maaaring i-drag para sa pagpapabuti ng pagiging nababasa. Ang dobleng pag-click sa isang node ay nagbubukas ng detalyadong impormasyon tungkol sa bagay: lahat ng mga katangian nito na may mga uri at halaga, stack ng tawag (backtrace) para sa bawat katangian at kasaysayan ng retain/release. Backtrace — ang pangunahing tampok: ipinapakita nito kung aling eksaktong linya ng code ang nagtatag ng sanggunian sa bagay. Ito ay nagbibigay-daan sa paghahanap ng pinagmulan ng tagas nang walang manu-manong pagrepaso sa buong code.

Para sa mga komplikadong graph, ang Xcode ay nagbibigay ng awtomatikong layout sa pamamagitan ng Layout → Hierarchical (hierarkikal) o Cluster (cluster). Ang hierarkikal na layout ay naglalagay ng mga root object sa itaas, mga anak na bagay sa ibaba, pinapadali ang paghahanap ng mga kadena. Ang cluster layout ay nag-grupo ng mga kaugnay na bagay sa mga cluster, na maginhawa kapag ang graph ay naglalaman ng ilang mga hiwalay na grupo. Ayon sa Apple, para sa karamihan ng mga application ay inirerekomenda ang hierarkikal na layout — ito ay intuitive at nangangailangan ng mas kaunting oras para sa biswal na pagsusuri.

lldb
// Mga utos ng LLDB na ginagamit ng Memory Graph sa ilalim ng hood
(lldb) script import lldb.macosx.heap
(lldb) script heap.find_variable("viewController")
0x600000c4b80: ViewController
(lldb) script heap.refs 0x600000c4b80
0x600000c4b80 -> 0x600003a4c00 (DataService)
    ivar: _service, offset: 16

Pagsusuri ng graph: paghahanap at pag-aalis ng mga tagas

Ang sistematikong paglapit sa pagsusuri ng Memory Graph ay may kasamang ilang yugto. Yugto 1: ilunsad ang application, isagawa ang senaryo na potensyal na nagdudulot ng tagas (buksan/isara ang screen, magsagawa ng network request). Yugto 2: pindutin ang Memory Graph button sa Debug Navigator — bubuo ang Xcode ng graph. Yugto 3: suriin ang mga orange na babala ng retain cycles sa kaliwang panel. Yugto 4: para sa mga kahina-hinalang bagay gamitin ang opsyon na Show only cycles — tanging mga node na kasama sa siklikal na sanggunian ang ipapakita.

Paggamit ng backtrace para sa paghahanap ng pinagmulan

Kapag natagpuan ang retain cycle, i-click ang gilid ng siklo at buksan ang panel ng inspektor. Sa seksyong Backtrace ay ipinapakita ang stack ng tawag sa sandaling itinatag ang sanggunian na ito. Halimbawa, kung ang gilid ay patungo mula closure patungo sa self, ang backtrace ay magpapakita kung saang pamamaraan at sa anong linya ng code nilikha ang closure. Tinatanggal nito ang pangangailangang manghula — agad mong makikita ang punto ng paglikha ng problematikong sanggunian. Ayon sa WWDC Labs, ang pagsusuri ng backtrace ay nagbabawas ng oras ng diagnosis ng retain cycle mula 15–20 minuto hanggang 2–3 minuto.

swift
class ProfileViewController: UIViewController {
    var profileView: ProfileView!

    override func viewDidLoad() {
        super.viewDidLoad()
        profileView = ProfileView()
        // Ipapakita ng Memory Graph ang retain cycle dito
        profileView.onTap = { [unowned self] in
            // ⚠️ Ang unowned ay maaaring magdulot ng crash sa nil self
            self.navigateToDetail()
        }
    }

    func navigateToDetail() { }
}

// ✅ Tama: [weak self] + guard let self
profileView.onTap = { [weak self] in
    guard let self else { return }
    self.navigateToDetail()
}

Pagsala ng mga hindi kinakailangang bagay

Ang Memory Graph ay maaaring magpakita ng libu-libong bagay, na nagpapahirap sa paghahanap. Gumamit ng mga filter sa kaliwang panel: ilagay ang pangalan ng klase (hal., ProfileViewController) upang ipakita lamang ang mga instance ng klaseng iyon. Pagkatapos piliin ang instance na dapat sana ay pinakawalan na (kung ang screen ay sarado ngunit ang bagay ay nanatili). Ilapat ang Show Reachable From — tanging mga sanggunian na may kaugnayan sa bagay na ito ang ipapakita, itatago ang natitirang graph.

Mga praktikal na tip sa paggamit ng Memory Graph

Ang mga may karanasang developer ay gumagamit ng Memory Graph hindi lamang para sa paghahanap ng mga tagas, kundi para din sa proaktibong kontrol ng memorya. Suriin ang Memory Graph pagkatapos ng bawat malaking pagbabago sa arkitektura — pagdaragdag ng bagong delegate, closure o subscription sa NotificationCenter. Sapat na isagawa ang isang tipikal na senaryo at tiyakin na ang mga bagay ay wastong pinapakawalan at ang retain cycles ay wala. Ito ay tumatagal ng 2–3 minuto, ngunit pumipigil sa oras ng pag-debug mamaya.

Kombinasyon sa Memory Report

Memory Report sa Xcode (tab na Debug Navigator) ay nagpapakita ng graph ng konsumo ng memorya sa real-time. Gamitin ito kasama ng Memory Graph: buksan ang Memory Graph sa biglaang pagtaas ng konsumo. Halimbawa, sa pag-scroll ng mahabang listahan na may mga cell na naglo-load ng mga imahe, ang Memory Graph ay magpapakita kung aling mga bagay ang nililikha at alin ang pinapakawalan. Kung ang bilang ng mga bagay ay tumataas nang walang pagbaba — ito ay potensyal na tagas, nakikita bago ito humantong sa crash. Ayon sa Apple, ang kombinasyon ng Memory Graph + Memory Report ay ang inirerekomendang workflow para sa lahat ng iOS developer simula sa Xcode 12.

objective-c
// Halimbawa ng tagas sa Objective-C sa pamamagitan ng delegasyon
@interface DownloadManager : NSObject
@property (strong) id delegate; // ❌ Dapat weak!
@end

@implementation DownloadManager
// Ipapakita ng Memory Graph ang retain cycle:
// ViewController → DownloadManager.delegate → ViewController
@end

// Pagwawasto: weak property
@property (weak) id delegate;

Pag-profile ng mga closure

Bigyan ng espesyal na atensyon ang mga closure — ang pinakakaraniwang pinagmulan ng retain cycles sa Swift. Kapag kumukuha ng self sa loob ng closure na iniimbak bilang pag-aari ng bagay, nabubuo ang isang klasikong siklo. Ipinapakita ito ng Memory Graph bilang isang closure (node na may simbolong {}), na konektado sa pamamagitan ng asul na mga gilid sa mga nakuhang bagay. Regular na suriin ang lahat ng closures, lalo na ang mga ginagamit sa mga asynchronous na tawag, GCD, Combine at SwiftUI. Ayon sa estadistika ng Point-Free, 90% ng mga tagas sa mga proyektong Swift ay may kaugnayan sa mga closure na kumukuha ng self.

Mga Madalas Itanong

Gumagana ba ang Memory Graph para lang sa Objective-C o para din sa Swift?

Gumagana ang Memory Graph para sa parehong wika, dahil ginagamit nito ang Objective-C runtime. Ang mga bagay na Swift na compatible sa ObjC (tagapagmana ng NSObject, minarkahan ng @objc) ay ganap na ipinapakita. Ang mga purong Swift na istruktura at klase na walang ObjC bridge ay limitadong nakikita.

Bakit hindi ipinapakita ng Memory Graph ang ilang bagay?

Ang mga bagay ay dapat naka-rehistro sa Objective-C runtime. Ang Swift value types (struct, enum) ay hindi ipinapakita. Tiyakin na ang klase ay nagmamana ng NSObject o gumagamit ng attribute na @objc para sa visibility sa Memory Graph.

Paano i-interpret ang mga kulay ng gilid sa graph?

Asul — strong reference, pinapanatili ang bagay. Berde — weak reference, hindi nakakaapekto sa lifecycle. Kulay-abo — unowned reference. Ang retain cycle ay nabubuo lamang mula sa mga asul na gilid.

Nagpapabagal ba ang Memory Graph ng application?

Ang pagbuo ng graph ay pumipigil sa application nang 1–3 segundo at maaaring pansamantalang tumaas ang konsumo ng memorya ng Xcode ng 200–500 MB. Ang application mismo ay hindi nagpapabagal, dahil ang inspeksyon ay nagaganap sa panahon ng pause sa breakpoint.

Maaari bang i-export ang Memory Graph para sa pagsusuri?

Hindi sinusuportahan ng Xcode ang direktang pag-export ng graph. Gumamit ng screenshot para sa dokumentasyon o lldb script na heap.find_variable para sa programatikong pagkuha ng data. Para sa detalyadong pagsusuri gamitin ang Instruments Allocations na may heap dump.

Buod

  • Memory Graph — biswal na kasangkapan ng Xcode para sa pagpapakita ng graph ng mga bagay sa memorya kasama ang kanilang mga sanggunian.
  • Retain cycle ay ipinapakita bilang isang saradong contour ng asul (strong) na mga gilid — iha-highlight ito ng Xcode ng orange.
  • Backtrace para sa bawat gilid ng graph ay nagpapakita ng eksaktong lokasyon sa code kung saan nilikha ang problematikong sanggunian.
  • Pagsala ayon sa mga klase at uri ng sanggunian ay nagbibigay-daan sa paghiwalay ng mga tagas sa graph na may libu-libong bagay.
  • Mga closure — pangunahing pinagmulan ng retain cycles sa Swift, ipinapakita sila ng Memory Graph bilang {} na mga node.
  • Weak at unowned — mga solusyon para sa pagputol ng siklo, ngunit ang weak ay mas gusto dahil sa kaligtasan sa nil.
  • Regular na pagsusuri ng Memory Graph pagkatapos ng mga pagbabago sa arkitektura ay pumipigil sa pag-regression ng memorya sa proyekto.

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din