iOS tool that helps with profiling iOS Memory usage.

Overview

FBMemoryProfiler

Carthage compatible CocoaPods

An iOS library providing developer tools for browsing objects in memory over time, using FBAllocationTracker and FBRetainCycleDetector.

About

This library shows how FBAllocationTracker and FBRetainCycleDetector can cooperate together, and how they can be used in real app.

It uses FBAllocationTracker to gather information about the objects. It supports generations and retain cycle detection.

Here is a small demo (project is available in Example directory)

Installation

Carthage

To your Cartfile add:

github "facebook/FBMemoryProfiler"

FBMemoryProfiler is built out from non-debug builds, so when you want to test it, use

carthage update --configuration Debug

CocoaPods

To your podspec add:

pod 'FBMemoryProfiler'

You'll be able to use FBMemoryProfiler fully only in Debug builds. This is controlled by compilation flag that can be provided to the build to make it work in other configurations.

Usage

To start using FBMemoryProfiler you'll first need to enable FBAllocationTracker.

#import <FBAllocationTracker/FBAllocationTrackerManager.h>

int main(int argc, char * argv[]) {
  [[FBAllocationTrackerManager sharedManager] startTrackingAllocations];
  [[FBAllocationTrackerManager sharedManager] enableGenerations];
  @autoreleasepool {
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}

To enable memory profiler:

#import <FBMemoryProfiler/FBMemoryProfiler.h>

FBMemoryProfiler *memoryProfiler = [FBMemoryProfiler new];
[memoryProfiler enable];

// Store memory profiler somewhere to extend it's lifetime
_memoryProfiler = memoryProfiler;

FBMemoryProfiler will show up as a button on the screen. Once tapped, it will open memory profiler in full size mode.

We can also define plugins (check below) and filters for retain cycle detector, that we pass to configuration.

_memoryProfiler = [[FBMemoryProfiler alloc] initWithPlugins:@[[IncredibleCacheCleaningPlugin new],
                                                              [AwesomeLoggerPlugin new]]
                           retainCycleDetectorConfiguration:someConfigurationWithCustomFilters];
[_memoryProfiler enable];

Plugins

Plugins are objects that conform to FBMemoryProfilerPluggable protocol. Example usage: custom cache cleaners, loggers that log data to server.

Contributing

See the CONTRIBUTING file for how to help out.

License

See (LICENSE)

Comments
  • FBMemoryProfiler message sent to deallocated crash on iOS 9.2.1

    FBMemoryProfiler message sent to deallocated crash on iOS 9.2.1

    I was really happy that finally these kinda tool was released to catch retained cycle which have been pain in my ass for a long time. I installed through Cocoapods, followed the instruction for basic setup and had played around with it. And guess what, it couldn't stay for a minute :( .It's 100% reproducible and steps are following:

    1. open app with FBMemoryProfiler
    2. toggle profile window
    3. click expand button
    4. click retain cycles

    FBRetainCycleUnits.m

    FBObjectiveCGraphElement *FBWrapObjectGraphElementWithContext(id object,
                                                                  FBObjectGraphConfiguration *configuration,
                                                                  NSArray<NSString *> *namePath) {
      if (FBObjectIsBlock((__bridge void *)object)) {
        return [[FBObjectiveCBlock alloc] initWithObject:object
                                          configuration:configuration
                                                namePath:namePath];
      } else {
        if ([object_getClass(object) isSubclassOfClass:[NSTimer class]] &&
            configuration.shouldInspectTimers) {
          return [[FBObjectiveCNSCFTimer alloc] initWithObject:object
                                                 configuration:configuration
                                                      namePath:namePath];
        } else {
          return [[FBObjectiveCObject alloc] initWithObject:object
                                              configuration:configuration
                                                   namePath:namePath];
        }
      }
    }
    
    //crash here
    FBObjectiveCGraphElement *FBWrapObjectGraphElement(id object,
                                                       FBObjectGraphConfiguration *configuration) {
      return FBWrapObjectGraphElementWithContext(object, configuration, nil);
    }
    

    screen shot 2016-04-14 at 10 28 02 pm

    Update: I followed the call stacks and found out that it happened when mutating a collection while enumeration. The call stack right before the crash is following:

        NSInteger tries = 10;
        for (NSInteger i = 0; i < tries; ++i) {
          // If collection is mutated we want to rollback and try again - let's keep refs in temporary set
          NSMutableSet *temporaryRetainedObjects = [NSMutableSet new];
          @try {
            for (id subobject in self.object) {
              if (retainsKeys) {
               //crash here
                [temporaryRetainedObjects addObject:FBWrapObjectGraphElement(subobject, self.configuration)];
              }
              if (isKeyValued && retainsValues) {
                [temporaryRetainedObjects addObject:FBWrapObjectGraphElement([self.object objectForKey:subobject],
                                                                             self.configuration)];
              }
            }
          }
          @catch (NSException *exception) {
            // mutation happened, we want to try enumerating again
            continue;
          }
    
    

    Update2: Turn on zombie objects and got following: [_UILabelLayer respondsToSelector:]: message sent to deallocated instance 0x110982130 0x0000000110982130

    I guess when tableview was filled with objects and clicking retain cycle (highlighting) caused the issue due to sending message to a object which is never allocated before? It seems working fine with few items

    bug 
    opened by intoxicated 18
  • UI is missing buttons, allocations, generations

    UI is missing buttons, allocations, generations

    I've followed your posted instructions: all 3 frameworks built via carthage, FBAllocationTrackerManager initialized in main(), and FBMemoryProfiler initialized in application:didFinishLaunchingWithOptions. I've turned off all of my appearance proxies and verified that my Large Text accessibility settings are off. I've tried on the simulator (6 and 6+) and on actual hardware (6S+).

    In all cases, the profiler UI comes up looking like this, with no entries, a truncated Mark Generations button, and missing buttons for Retain Cycles and Expand. The memory readout changes as I interact with the app, so some part of it is working correctly.

    Any ideas on what could be wrong? screen shot 2016-04-21 at 11 41 47 am

    opened by eliburke 13
  • Crash for empty ClassNames

    Crash for empty ClassNames

    FBAllocationTrackerSummary instances with className being nil crash the Retain Cycle detection.

    You could just filter nil entries in [FBMemoryProfilerDataSource _refilterSectionAtIndex:] but I guess we should find out, why a className can be nil in the first place.

    This is a the Quickfix I implemented:

    FBMemoryProfilerDataSource
    - (NSArray *)_refilterSectionAtIndex:(NSInteger)index
    {
      NSArray *filtered = [_data[index] filteredArrayUsingPredicate:
                           [NSPredicate predicateWithBlock:^BOOL(FBAllocationTrackerSummary *entry, NSDictionary *bindings) {
        NSString *className = entry.className.lowercaseString;
        if (_classFilter && [className rangeOfString:_classFilter].location == NSNotFound) {
          return NO;
        }
    
        if (entry.aliveObjects > 0 && entry.className) {
          return YES;
        }
    
        return NO;
      }]];
    }
    
    opened by absolute-heike 5
  • Fix crash when repo's description is empty.

    Fix crash when repo's description is empty.

    The JSON objects from the request of https://api.github.com/orgs/facebook/repos?per_page=300 may conatin null value, like the repo https://github.com/facebook/caf8teen, there is no repo description, when you create GithubRepository object, the shortDescription's value is [NSNull null]. When you want to show the repos list, it will crash when executing cell.detailTextLabel.text = _data[indexPath.row].shortDescription;.

    In the example, we only use three values, repo's name, description, html_url, the name and url must be valid, only the description my has nothing.

    Environment: Xcode 8.1 beta2, Simulator iPhone 7 Plus

    CLA Signed GH Review: review-needed 
    opened by mrmign 4
  • Profiler Button Does not appear after adding profiler to the Project

    Profiler Button Does not appear after adding profiler to the Project

    I have added memory profile to the Objective-C project and initialised project but the Profile button is not appearing on the screen.

     [[FBAllocationTrackerManager sharedManager] startTrackingAllocations];
        [[FBAllocationTrackerManager sharedManager] enableGenerations];
    
    
        FBMemoryProfiler *memoryProfiler = [FBMemoryProfiler new];
        [memoryProfiler enable];
    
    opened by ajaybeniwal 3
  • Find lots of cycle about runtime above iOS10

    Find lots of cycle about runtime above iOS10

    {( ( "-> NWConcrete_nw_resolver ", "-> update_block -> NSMallocBlock " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> viability_changed_handler -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> connected_child -> NWConcrete_nw_endpoint_handler ", "-> parent_handler -> NWConcrete_nw_endpoint_handler ", "-> mode_handler -> NWConcrete_nw_endpoint_resolver " ), ( "-> NWConcrete_nw_endpoint_handler ", "-> mode_handler -> NWConcrete_nw_endpoint_resolver ", "-> resolver -> NWConcrete_nw_resolver ", "-> update_block -> NSMallocBlock " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> parent_endpoint_handler -> NWConcrete_nw_endpoint_handler ", "-> tls_prepare_block -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> parent_endpoint_handler -> NWConcrete_nw_endpoint_handler ", "-> tls_message_block -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> connected_endpoint_handler -> NWConcrete_nw_endpoint_handler ", "-> parent_handler -> NWConcrete_nw_endpoint_handler ", "-> tls_message_block -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> parent_endpoint_handler -> NWConcrete_nw_endpoint_handler ", "-> mode_handler -> NWConcrete_nw_endpoint_resolver ", "-> connected_child -> NWConcrete_nw_endpoint_handler ", "-> tls_prepare_block -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> connected_endpoint_handler -> NWConcrete_nw_endpoint_handler ", "-> parent_handler -> NWConcrete_nw_endpoint_handler ", "-> tls_prepare_block -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> path_changed_handler -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> client_handler -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> read_close_handler -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> connected_endpoint_handler -> NWConcrete_nw_endpoint_handler ", "-> tls_prepare_block -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> write_close_handler -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> better_path_available_handler -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> parent_endpoint_handler -> NWConcrete_nw_endpoint_handler ", "-> mode_handler -> NWConcrete_nw_endpoint_resolver ", "-> connected_child -> NWConcrete_nw_endpoint_handler ", "-> tls_message_block -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ), ( "-> tc_nwconn -> NWConcrete_nw_connection ", "-> connected_endpoint_handler -> NWConcrete_nw_endpoint_handler ", "-> tls_message_block -> NSMallocBlock ", "-> NWConcrete_tcp_connection " ) )}

    opened by liuzhiyi1992 2
  • FBAllocationTrackerSummary nil className crash

    FBAllocationTrackerSummary nil className crash

    Thanks a lot for taking the time to create this tool! ARC makes it easier to code, because it's still easy to create retain cycles or not create memory pressure because of missing autoreleasepool usage.

    About the crash: It can happen, that there are FBAllocationTrackerSummary instances with nil className. This will result in a crash in the FBMemoryProfilerDataSource's classNamesForSection: method.

    Sometimes I can constantly reproduce it, sometimes it disappears. I've seen it both on device and simulator.

    screen shot 2016-04-29 at 4 42 28 pm

    I've tried to look into this and the FBAllocationTrackerSummary do get created with an empty class name:

    screen shot 2016-04-29 at 5 06 04 pm

    Also a screenshot about the kv instance state in the FBAllocationTrackerManager.mm's _getSingleGenerationSummary, when the FBAllocationTrackerSummary is created.

    slice2

    I hope that this is helpful :)

    opened by ilsinszkibal 2
  • FBAllocationTrackerSummary.className cause crash

    FBAllocationTrackerSummary.className cause crash

    Though your define @property (nonatomic, copy, readonly, nonnull) NSString *className; It maybe nil. In FBMemoryProfilerDataSource the 241 line.[array addObject:object.className] may add nil.

    opened by c-xiaoqiang 2
  • Misjudged on retained cycle

    Misjudged on retained cycle

    Hi, we use FBMemoryProfiler in my project, but I found some misjudged retained cycle. In the code, using FBObjectiveCGraphElement to save the information of retain cycled object. But the property of FBObjectiveCGraphElement object is weak. When I checked a retained cycle, and notify the observers, at the same time, the retained cycle have been broken, the object was deallocated. Finally the observers receive a retained cycle chain like this: ( "-> _traitCollection -> (null) ", "-> _image -> (null) ", "-> _borderImageHL -> (null) " ) I think it is not retained cycle. I don't know if I have some wrong in the analysis. Could you check it?

    opened by without2002 1
  • Retain cycles's cell is red,but when I tap, it still to find retain cycles again.

    Retain cycles's cell is red,but when I tap, it still to find retain cycles again.

    I just want to find it once.But it has to find retain cycle every time.Can you support it?

    • (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Retain cycle detection kicks in NSString *className = [tableView cellForRowAtIndexPath:indexPath].textLabel.text; NSInteger generationIndex = indexPath.section;

      [self _findRetainCyclesForClassesNamed:@[className] inGeneration:generationIndex presentDetails:YES]; }

    opened by c-xiaoqiang 1
  • [Podspec] Set platform to 7.0

    [Podspec] Set platform to 7.0

    Description

    This pull request allows projects with a deployment target of iOS 7.0 to integrate FBMemoryProfiler.

    Note

    The podspecs of FBMemoryProfilers dependencies have to be changed as well: https://github.com/facebook/FBAllocationTracker/pull/5 https://github.com/facebook/FBRetainCycleDetector/pull/5

    CLA Signed GH Review: accepted 
    opened by HeEAaD 1
  • Why can't detect the memory leak in my case ?

    Why can't detect the memory leak in my case ?

    I wrote a ViewController to test memory leak detection, but I found that the log did not detect it. Why?

    The ViewController is written like this:

    @interface TableView : NSObject
    @property(nonatomic) Byte *space;
    @property(nonatomic, copy) void (^block)();
    -(void)sayHello;
    @end
    
    #define kTenMB  1048576 * 10
    @implementation TableView
    - (instancetype)init {
        self = [super init];
        if (self) {
            //分配 10MB 内存
            self.space = malloc(kTenMB);
            memset(self.space, 0, kTenMB);
        }
        return self;
    }
    -(void)sayHello {
        NSLog(@"Hello!");
    }
    - (void)dealloc {
        NSLog(@"=== %s",__func__);
        free(self.space);
    }
    @end
    
    
    @interface AViewController ()
    @property(nonatomic, copy) void (^block)();
    @property(nonatomic, strong) TableView *tableView;
    
    @end
    
    @implementation AViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        self.title = @"A";
        self.view.backgroundColor = UIColor.greenColor;
        
    // ---- Block ,self leak ----
       self.block = ^{
    //        [self test];
           NSLog(@"== title:%@",self.title);
       };
       self.block();
    
       // ---- tableView leak ----
       TableView *tableView = [TableView new];
       tableView.block = ^{
           [tableView sayHello];
       };
        
    }
    -(void)test{
        NSLog(@"==== %s %@",__func__,self);
    
    }
    - (void)dealloc {
        NSLog(@"==== %s %@",__func__,self);
    }
    
    @end
    

    The configuration of FBMemoryProfiler is like this: main.m

    #import <UIKit/UIKit.h>
    #import <FBAllocationTracker/FBAllocationTrackerManager.h>
    #import <FBRetainCycleDetector/FBRetainCycleDetector.h>
    #import "AppDelegate.h"
    
    int main(int argc, char *argv[]) {
       [FBAssociationManager hook];
       [[FBAllocationTrackerManager sharedManager] startTrackingAllocations];
       [[FBAllocationTrackerManager sharedManager] enableGenerations];
    
        NSString *appDelegateClassName;
        @autoreleasepool {
            // Setup code that might create autoreleased objects goes here.
            appDelegateClassName = NSStringFromClass([AppDelegate class]);
        }
        return UIApplicationMain(argc, argv, nil, appDelegateClassName);
    }
    

    AppDelegate.m

    #import <FBMemoryProfiler/FBMemoryProfiler.h>
    #import <FBRetainCycleDetector/FBRetainCycleDetector.h>
    #import "AppDelegate.h"
    
    @interface RetainCycleLoggerPlugin : NSObject <FBMemoryProfilerPluggable>
    @end
    @implementation RetainCycleLoggerPlugin
    
    - (void)memoryProfilerDidFindRetainCycles:(NSSet *)retainCycles {
       NSLog(@"=== cycle retains:%@\n", retainCycles);
    }
    @end
    
    
    @interface AppDelegate () {
        FBMemoryProfiler *_memoryProfiler;
    }
    @end
    
    @implementation AppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
       _memoryProfiler = [[FBMemoryProfiler alloc] initWithPlugins:@[[RetainCycleLoggerPlugin new]] retainCycleDetectorConfiguration:nil];
       [_memoryProfiler enable];
    
        return YES;
    }
    
    @end
    
    opened by luowei 0
  • Semantic Issue 'Array has incomplete element type' when building

    Semantic Issue 'Array has incomplete element type' when building

    Tried building the project in both Xcode 9.2 and 9.3 and ran into the semantic issue "Array has incomplete element type 'struct rcd _rebranding'" on lines 164 and 184 inFBAssociationManager.

    screen shot 2018-05-11 at 1 05 57 pm

    opened by abbyThompson 1
Owner
Facebook Archive
These projects have been archived and are generally unsupported, but are still available to view and use
Facebook Archive
Find memory leaks in your iOS app at develop time.

中文介绍 | FAQ中文 MLeaksFinder MLeaksFinder helps you find memory leaks in your iOS apps at develop time. It can automatically find leaks in UIView and UIV

Tencent 5.3k Dec 22, 2022
Find memory issues & leaks in your iOS app without instruments

HeapInspector Find memory issues & leaks in your iOS app HeapInspector is a debug tool that monitors the memory heap with backtrace recording in your

Christian Menschel 1.8k Nov 24, 2022
Simple iOS app blackbox assessment tool. Powered by frida.re and vuejs.

Discontinued Project This project has been discontinued. Please use the new Grapefruit #74 frida@14 compatibility issues frida@14 introduces lots of b

Chaitin Tech 1.6k Dec 16, 2022
A linter tool for Interface Builder

IBLinter A linter tool to normalize .xib and .storyboard files. Inspired by realm/SwiftLint Installation Using Homebrew $ brew install iblinter Using

IBDecodable 945 Nov 11, 2022
A tool for Swift code modification intermediating between code generation and formatting.

swift-mod A tool for Swift code modification intermediating between code generation and formatting. Overview swift-mod is a tool for Swift code modifi

Ryo Aoyama 95 Nov 3, 2022
A command-line tool and Xcode Extension for formatting Swift code

Table of Contents What? Why? How? Command-line tool Xcode source editor extension Xcode build phase Via Applescript VSCode plugin Sublime Text plugin

Nick Lockwood 6.3k Jan 8, 2023
A tool to enforce Swift style and conventions.

SwiftLint A tool to enforce Swift style and conventions, loosely based on the now archived GitHub Swift Style Guide. SwiftLint enforces the style guid

Realm 16.9k Jan 9, 2023
A static source code analysis tool to improve quality and reduce defects for C, C++ and Objective-C

OCLint - https://oclint.org OCLint is a static code analysis tool for improving quality and reducing defects by inspecting C, C++ and Objective-C code

The OCLint Static Code Analysis Tool 3.6k Dec 29, 2022
iOS project bootstrap aimed at high quality coding.

iOS Project bootstrap How do you setup your iOS projects? Since we are approaching 2015 I’m working on refreshing my project bootstrap. I’ve decided t

Krzysztof Zabłocki 2k Dec 23, 2022
iOS library to help detecting retain cycles in runtime.

FBRetainCycleDetector An iOS library that finds retain cycles using runtime analysis. About Retain cycles are one of the most common ways of creating

Facebook 4.1k Dec 26, 2022
Awesome bug reporting for iOS apps

Buglife is an awesome bug reporting SDK & web platform for iOS apps. Here's how it works: User takes a screenshot, or stops screen recording User anno

Buglife 498 Dec 17, 2022
Makes it easier to support older versions of iOS by fixing things and adding missing methods

PSTModernizer PSTModernizer carefully applies patches to UIKit and related Apple frameworks to fix known radars with the least impact. The current set

PSPDFKit Labs 217 Aug 9, 2022
decoupling between modules in your iOS Project. iOS模块化过程中模块间解耦方案

DecouplingKit 中文readme Podfile platform :ios, '7.0' pod 'DecouplingKit', '~> 0.0.2' DecouplingKit, decoupling between modules in your iOS Project. D

coderyi 139 Aug 23, 2022
Flexible bug report framework for iOS

Clue is a simple smart-bug report framework for iOS, which allows your users to record full bug/crash report and send it to you as a single .clue file

Ahmed Sulaiman 279 Nov 3, 2022
The project used in the iOS Architect Crash Course lectures

iOS Architect Crash Course • August 2nd-8th • EssentialDeveloper.com https://www.essentialdeveloper.com/ios-architect-crash-course/aug-2021-a5220 It's

Aleksei Korolev 1 Jul 20, 2022
Skredvarsel app - an iOS, iPadOS, and macOS application that provides daily avalanche warnings from the Norwegian Avalanche Warning Service API

Skredvarsel (Avalanche warning) app is an iOS, iPadOS, and macOS application that provides daily avalanche warnings from the Norwegian Avalanche Warning Service API

Jonas Follesø 8 Dec 15, 2022
A library that enables dynamically rebinding symbols in Mach-O binaries running on iOS.

fishhook fishhook is a very simple library that enables dynamically rebinding symbols in Mach-O binaries running on iOS in the simulator and on device

Meta 4.9k Jan 8, 2023
A command line profiling tool with stopwatch, cpu and memory usage

timeui A command line profiling tool with stopwatch, cpu and memory usage. Usage ./timeui path/to/app-to-profile runs the stopwatch and signpost regio

Marin Todorov 107 Dec 10, 2022
Profiling / Debugging assist tools for iOS. (Memory Leak, OOM, ANR, Hard Stalling, Network, OpenGL, Time Profile ...)

MTHawkeye Readme 中文版本 MTHawkeye is profiling, debugging tools for iOS used in Meitu. It's designed to help iOS developers improve development producti

meitu 1.4k Dec 29, 2022
In-app memory usage monitoring for iOS

What's Stats Stats displays load statuses such as the memory usage, the CPU load, and the number of subviews in-app, and in realtime. How to use Just

Shuichi Tsutsumi 170 Sep 18, 2022