Code Monkey home page Code Monkey logo

fbmemoryprofiler's Introduction

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)

fbmemoryprofiler's People

Contributors

absolute-heike avatar adelmezara avatar dahlgren avatar kastiglione avatar kparentfb avatar minaeng avatar youngdfb avatar zpao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fbmemoryprofiler's Issues

Crash EXC_BAD_ACCESS

I have activated FBMemoryProfiler in my project and it cause quickly a crash.
I suppose it's an access to my NSPersistentStoreCoordinator...

#import <UIKit/UIKit.h>
#import "MyAppDelegate.h"
#import <FBAllocationTracker/FBAllocationTrackerManager.h>
#import <FBMemoryProfiler/FBMemoryProfiler.h>

int main(int argc, char *argv[])
{
    int retVal = 0;
    @autoreleasepool {
        [[FBAllocationTrackerManager sharedManager] startTrackingAllocations];
        [[FBAllocationTrackerManager sharedManager] enableGenerations];
        FBMemoryProfiler *memoryProfiler = [FBMemoryProfiler new];
        [memoryProfiler enable];
        retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([MyAppDelegate class]));
    }
    return retVal;
}

capture d ecran 2016-04-29 a 17 00 35

How to import this tool to project manually ?

I've try to manually add these project to my project, but I meet a problem which same as a close issue: "UI is missing buttons, allocations, generations". How can I fix it?

By the way, I have set DEBUG = 1

NO retainCycle button

I cannot find the 'retaincycle' button when I load my app.
Here is the photo. @theNightLign
wechatimg65

can you dump memory?

hi,this day
i try to dump memory and relationship.when i see this tool,i think may be you can dump it ?
like:hook malloc and free and scan the ptr?

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

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

EXC_BAD_ACCESS when press retain cycles

Hi,
there was a crashes when tap on retain cycles and this is happened consistently
I was not sure what caused the problem,

the crashed seems happened in FBAllocationTrackerGeneration.mm class

screen shot 2016-11-18 at 4 05 24 pm

Thanks,

keyboard can't showup

In release mode, it can show normally.But in debug mode, why keyboard can't showup?

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

Swift

I presume that this is completely incompatible with Swift code?

If it is, is Swift support somewhere on the radar?

not found .framework

I download this project, but I can not found the .framework file.
must use cocoapods? I really do not want use this tool.

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];

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

FBMemoryProfiler crash with __NSCFCalendar,_screenPageMap.

I have test the FBMemoryProfiler in my project and cause some crash:

  1. FBObjectiveCObject ->subobject->0xffffffffffffffff & namePath = @"_screenPageMap":

fbtest1

when I filter it the crash fixed.
if ([self.namePath[0] isEqualToString:@"_screenPageMap"]) { NSLog(@""); return retainedObjects; }

  1. FBAllocationTrackerManager:- (NSArray *)instancesForClass:(__unsafe_unretained Class)aCls inGeneration:(NSInteger)generation
    fbtest2
    fbtest3

in FBAllocationTrackerImpl std::vector<id> instancesOfClassForGeneration I filter it with code:
if ([NSStringFromClass(aCls) isEqualToString:@"__NSCFCalendar"]) { return std::vector<id> {}; }

then my project run complete with retain cycles button tap.

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

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 :)

Support for Extensions?

Does this support profiling memory on application extensions, such as the PacketTunnelProvider?

FBMemoryProfiler button doesn't appear on the screen

Steps to reproduce:

  1. Created new xcode project
  2. Installed FBMemoryProfiler pod
  3. Added code to app delegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    FBMemoryProfiler *memoryProfiler = [FBMemoryProfiler new];
    [memoryProfiler enable];

    return YES;
}

Then added code to main.m

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

Run app..Result: Empty screen without button.

What did I missed ?

FBMemoryProfile won't match XCode Debug gauges

Use Unity build a game App. when the unity scene unloaded the xcode memory from 400M drop to 200m, but the FBMemoryProfile still around 400M.
I also use the mach_task_basic_info and host_statistics API, it also dose't match the XCode Debug gagues, is there any other solution to get Ram usage by the App on IOS?

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?

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.