diff --git a/.gitignore b/.gitignore index 8a03e31..8aba4d0 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ ## Build generated build/ DerivedData/ +*.DS_Store ## Various settings *.pbxuser diff --git a/Demo/OOMDetector.xcodeproj/project.pbxproj b/Demo/OOMDetector.xcodeproj/project.pbxproj index 940ae59..b8db618 100644 --- a/Demo/OOMDetector.xcodeproj/project.pbxproj +++ b/Demo/OOMDetector.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 4AE2C5E220883ACC0042D00B /* libOOMDetector.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4AE2C5E120883ACC0042D00B /* libOOMDetector.framework */; }; 6B12C6421F9621F9000B42F0 /* DemoListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B12C6411F9621F9000B42F0 /* DemoListViewController.m */; }; 6B12C6461F962E14000B42F0 /* DemoViewController0.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B12C6451F962E14000B42F0 /* DemoViewController0.m */; }; 6B12C6491F962EA9000B42F0 /* DemoViewController1.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B12C6481F962EA9000B42F0 /* DemoViewController1.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; @@ -16,12 +17,14 @@ 6B9A04F51FD5823800414B1F /* BaseDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B8C22E71F8E494C007DE399 /* BaseDemoViewController.m */; }; 6B9A04F61FD5823800414B1F /* DemoViewController2.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B12C7011F974AB8000B42F0 /* DemoViewController2.m */; }; 6B9A04F71FD5823800414B1F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B8C22E41F8E494C007DE399 /* AppDelegate.m */; }; - 6BADA10D1FA8AC0F00668479 /* DemoViewController3.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BADA10C1FA8AC0F00668479 /* DemoViewController3.m */; }; + 6BADA10D1FA8AC0F00668479 /* DemoViewController3.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BADA10C1FA8AC0F00668479 /* DemoViewController3.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 6BF6879C1FC3C4D500054160 /* MyOOMDataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BF6879B1FC3C4D500054160 /* MyOOMDataManager.m */; }; - 7DE3285020107E9B007A188B /* libOOMDetector.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7DE3285120107E9B007A188B /* libOOMDetector.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 4A9C1E3A208499EC00E54134 /* libOOMDetector_QQ.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = libOOMDetector_QQ.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4A9C1E3C20849A7800E54134 /* libOOMDetector.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = libOOMDetector.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4AE2C5E120883ACC0042D00B /* libOOMDetector.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = libOOMDetector.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6B12C6401F9621F9000B42F0 /* DemoListViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DemoListViewController.h; sourceTree = ""; }; 6B12C6411F9621F9000B42F0 /* DemoListViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DemoListViewController.m; sourceTree = ""; }; 6B12C6441F962E14000B42F0 /* DemoViewController0.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DemoViewController0.h; sourceTree = ""; }; @@ -51,7 +54,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7DE3285020107E9B007A188B /* libOOMDetector.framework in Frameworks */, + 4AE2C5E220883ACC0042D00B /* libOOMDetector.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -113,6 +116,9 @@ 6B9A04F21FD5816F00414B1F /* Frameworks */ = { isa = PBXGroup; children = ( + 4AE2C5E120883ACC0042D00B /* libOOMDetector.framework */, + 4A9C1E3C20849A7800E54134 /* libOOMDetector.framework */, + 4A9C1E3A208499EC00E54134 /* libOOMDetector_QQ.framework */, 7DE3285120107E9B007A188B /* libOOMDetector.framework */, ); name = Frameworks; @@ -329,19 +335,23 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 8D5EHT9KTL; + DEVELOPMENT_TEAM = JVT843N4EQ; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", Build_For_Extern, ); INFOPLIST_FILE = OOMDetectorDemo/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; NEW_SETTING = ""; ONLY_ACTIVE_ARCH = NO; - OTHER_LDFLAGS = "-lc++"; - PRODUCT_BUNDLE_IDENTIFIER = com.tencentgsd.OOMDemo; + OTHER_LDFLAGS = ( + "-lc++", + "-force_load", + "$(BUILT_PRODUCTS_DIR)/libOOMDetector.framework/libOOMDetector", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.tencent.rosen; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -357,14 +367,18 @@ CLANG_ENABLE_OBJC_ARC = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 8D5EHT9KTL; + DEVELOPMENT_TEAM = JVT843N4EQ; GCC_PREPROCESSOR_DEFINITIONS = Build_For_Extern; INFOPLIST_FILE = OOMDetectorDemo/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; NEW_SETTING = ""; - OTHER_LDFLAGS = "-lc++"; - PRODUCT_BUNDLE_IDENTIFIER = com.tencentgsd.OOMDemo; + OTHER_LDFLAGS = ( + "-lc++", + "-force_load", + "$(BUILT_PRODUCTS_DIR)/libOOMDetector.framework/libOOMDetector", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.tencent.rosen; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/Demo/OOMDetector.xcodeproj/xcuserdata/rosen.xcuserdatad/xcschemes/xcschememanagement.plist b/Demo/OOMDetector.xcodeproj/xcuserdata/rosen.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index eaac3a5..0000000 --- a/Demo/OOMDetector.xcodeproj/xcuserdata/rosen.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - SchemeUserState - - OOMDetector.xcscheme - - orderHint - 1 - - - - diff --git a/Demo/OOMDetectorDemo/AppDelegate.m b/Demo/OOMDetectorDemo/AppDelegate.m index 1510199..e8a60ac 100644 --- a/Demo/OOMDetectorDemo/AppDelegate.m +++ b/Demo/OOMDetectorDemo/AppDelegate.m @@ -19,6 +19,23 @@ #import "AppDelegate.h" #import "MyOOMDataManager.h" #import "DemoListViewController.h" +#import +#import +#import +#import + +#define USE_VM_LOGGER + +#ifdef USE_VM_LOGGER +typedef void (malloc_logger_t)(uint32_t type, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t result, uint32_t num_hot_frames_to_skip); + +extern malloc_logger_t* __syscall_logger; +#endif + +static void oom_log_callback(char *info) +{ + NSLog(@"%s",info); +} @import libOOMDetector; @@ -31,13 +48,49 @@ @interface AppDelegate () @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [self setupWindow]; + [[OOMDetector getInstance] registerLogCallback:oom_log_callback]; + [self setupFOOMMonitor]; [self setupOOMDetector]; - return YES; } +- (void)applicationWillTerminate:(UIApplication *)application +{ + [[FOOMMonitor getInstance] appWillTerminate]; +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + [[FOOMMonitor getInstance] appDidEnterBackground]; +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + [[FOOMMonitor getInstance] appWillEnterForground]; +} + +- (void)applicationDidCrashed +{ + //crash 捕获组件的回调 + [[FOOMMonitor getInstance] appDidCrashed]; +} + +- (void)applicationDetectedDeadlock +{ + //检测到死锁,可以使用blue组件捕获 + //[[QQBlueFrameMonitor getInstance] startDeadLockMonitor:^(double cost, NSArray *stacks) { +// [[FOOMMonitor getInstance] appDetectDeadLock:stacks]; +//}]; + [[FOOMMonitor getInstance] appDetectDeadLock:nil]; +} + +- (void)applicationResumeFromDeadlock +{ + //从死锁恢复 + [[FOOMMonitor getInstance] appResumeFromDeadLock]; +} + - (void)setupWindow { self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; @@ -46,6 +99,13 @@ - (void)setupWindow [self.window makeKeyAndVisible]; } +- (void)setupFOOMMonitor +{ + [[FOOMMonitor getInstance] setAppVersion:@"OOMDetector_demo"]; + //设置爆内存监控,爆内存监控用于监控App前台爆内存和卡死,这个可以全量开启 + [[FOOMMonitor getInstance] start]; +} + - (void)setupOOMDetector { OOMDetector *detector = [OOMDetector getInstance]; @@ -56,31 +116,53 @@ - (void)setupOOMDetector // 设置捕获堆栈数据、内存log代理,在出现单次大块内存分配、检查到内存泄漏且时、调用uploadAllStack方法时会触发此回调 [detector setFileDataDelegate:[MyOOMDataManager getInstance]]; - - // 设置app内存触顶监控数据代理,在调用startMaxMemoryStatistic:开启内存触顶监控后会触发此回调,返回前一次app运行时单次生命周期内的最大物理内存数据 +// +// // 设置app内存触顶监控数据代理,在调用startMaxMemoryStatistic:开启内存触顶监控后会触发此回调,返回前一次app运行时单次生命周期内的最大物理内存数据 [detector setPerformanceDataDelegate:[MyOOMDataManager getInstance]]; - - // 单次大块内存分配监控 +// +// // 单次大块内存分配监控 [detector startSingleChunkMallocDetector:50 * 1024 * 1024 callback:^(size_t bytes, NSString *stack) { [[NSNotificationCenter defaultCenter] postNotificationName:kChunkMallocNoti object:stack]; }]; - // 开启内存泄漏监控,目前只可检测真机运行时的内存泄漏,模拟器暂不支持 + // 开启内存泄漏监控,目前只可检测真机运行时的内存泄漏,模拟器暂不支持,这个功能占用的内存较大,建议只在测试阶段使用 [detector setupLeakChecker]; - // 开启MallocStackMonitor用以监控通过malloc方式分配的内存 - [detector startMallocStackMonitor:10 * 1024 * 1024 needAutoDumpWhenOverflow:YES dumpLimit:300 sampleInterval:0.1]; - - // 开启VMStackMonitor用以监控非直接通过malloc方式分配的内存 - // 因为startVMStackMonitor:方法用到了私有API __syscall_logger会带来app store审核不通过的风险,此方法默认只在DEBUG模式下生效,如果 - // 需要在RELEASE模式下也可用,请打开USE_VM_LOGGER_FORCEDLY宏,但是切记在提交appstore前将此宏关闭,否则可能会审核不通过 - [detector startVMStackMonitor:10 * 1024 * 1024]; - - // 调用该接口上报所有缓存的OOM相关log给通过setFileDataDelegate:方法设置的代理,建议在启动的时候调用 - [detector uploadAllStack]; + // 开启MallocStackMonitor用以监控通过malloc方式分配的内存,会增加8%左右的cpu开销和10Mb内存,所以建议抽样开启 + [detector startMallocStackMonitor:30 * 1024 * 1024 logUUID:[[FOOMMonitor getInstance] getLogUUID]]; + //30K以下堆栈按10%抽样监控 +// OOMDetector *oomdetector = [OOMDetector getInstance]; +// [oomdetector setMallocSampleFactor:10]; +// [oomdetector setMallocNoSampleThreshold:30*1024]; +// // 开启VMStackMonitor用以监控非直接通过malloc方式分配的内存 +// // 因为startVMStackMonitor:方法用到了私有API __syscall_logger会带来app store审核不通过的风险,此方法默认只在DEBUG模式下生效,如果 +// // 需要在RELEASE模式下也可用,请打开USE_VM_LOGGER_FORCEDLY宏,但是切记在提交appstore前将此宏关闭,否则可能会审核不通过 +// [detector setVMLogger:(void**)&__syscall_logger]; +// [detector startVMStackMonitor:30 * 1024 * 1024 logUUID:[[FOOMMonitor getInstance] getLogUUID]]; /*************************************************************************/ } +-(void)testmmap +{ + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); + NSString *LibDirectory = [paths objectAtIndex:0]; + NSString *path = [LibDirectory stringByAppendingPathComponent:@"test.log"]; + FILE *fp = fopen ( [path fileSystemRepresentation] , "wb+" ) ; + char *ptr = (char *)mmap(0, 50*1024*1024, PROT_WRITE | PROT_READ, (MAP_FILE|MAP_SHARED), fileno(fp), 0); + munmap(ptr,50*1024*1024); +} + +-(void)performanceData:(NSDictionary *)data completionHandler:(void (^)(BOOL))completionHandler +{ + //上报 +} + +/** 在出现单次大块内存分配、检查到内存泄漏且时、调用uploadAllStack方法时触发回调 */ +-(void)fileData:(id)data extra:(NSDictionary *)extra type:(QQStackReportType)type completionHandler:(void (^)(BOOL))completionHandler +{ + //上报 +} + @end diff --git a/Demo/OOMDetectorDemo/Demos/DemoViewController0.m b/Demo/OOMDetectorDemo/Demos/DemoViewController0.m index c3e5644..500fa9b 100644 --- a/Demo/OOMDetectorDemo/Demos/DemoViewController0.m +++ b/Demo/OOMDetectorDemo/Demos/DemoViewController0.m @@ -62,7 +62,14 @@ - (void)checkLeak - (void)runDemoCode { - Demo0Code + for(int i = 0; i < 600000; i++){ + char *test1 = malloc(1024); + memset(test1, 0, 1024); + if(i % 2 == 0){ + free(test1); + } + } +// Demo0Code } - (NSString *)demoCodeText diff --git a/Demo/OOMDetectorDemo/Demos/DemoViewController2.m b/Demo/OOMDetectorDemo/Demos/DemoViewController2.m index 17a30f3..65613de 100644 --- a/Demo/OOMDetectorDemo/Demos/DemoViewController2.m +++ b/Demo/OOMDetectorDemo/Demos/DemoViewController2.m @@ -61,7 +61,12 @@ - (void)onReceiveChunkMallocNoti:(NSNotification *)noti - (void)runDemoCode { - DemoCode2 + int size = 51 * 1024 * 1024; + char *info = malloc(size); + memset(info, 1, size); +// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\ +// free(info); +// }); } - (NSString *)demoCodeText diff --git a/Demo/OOMDetectorDemo/Demos/DemoViewController3.m b/Demo/OOMDetectorDemo/Demos/DemoViewController3.m index ccfa2db..46cc2d3 100644 --- a/Demo/OOMDetectorDemo/Demos/DemoViewController3.m +++ b/Demo/OOMDetectorDemo/Demos/DemoViewController3.m @@ -22,20 +22,6 @@ @import libOOMDetector; -#define DemoCode3 \ -int i = 0;\ -while (i < 3000) {\ - [self.arr addObject:[[NSObject alloc] init]];\ - ++i;\ -}\ - -@interface DemoViewController3 () - -@property (nonatomic, strong) NSTimer *timer; -@property (nonatomic, strong) NSMutableArray *arr; - -@end - @implementation DemoViewController3 - (void)viewDidLoad @@ -44,18 +30,11 @@ - (void)viewDidLoad self.isOOMDemo = YES; self.resultLabel.hidden = YES; - self.arr = [NSMutableArray new]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; - - [self.timer invalidate]; - self.timer = nil; - - [self.arr removeAllObjects]; - self.arr = nil; } - (NSString *)demoDescriptionString @@ -65,15 +44,15 @@ - (NSString *)demoDescriptionString - (void)runDemoCode { - if (!self.timer) { - self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(test) userInfo:nil repeats:YES]; - [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes]; - } + [self test]; } - (void)test { - DemoCode3 + while (1) { + NSObject *obj = [[[NSObject alloc] init] retain]; + [obj class]; + } } - (NSString *)demoCodeText diff --git a/Demo/OOMDetectorDemo/MyOOMDataManager.m b/Demo/OOMDetectorDemo/MyOOMDataManager.m index 20f7b44..9420f1f 100644 --- a/Demo/OOMDetectorDemo/MyOOMDataManager.m +++ b/Demo/OOMDetectorDemo/MyOOMDataManager.m @@ -45,9 +45,13 @@ - (void)fileData:(NSData *)data extra:(NSDictionary *)ext if (type == QQStackReportTypeOOMLog) { // 此处为了Demo演示需要传参数NO,NO表示我们自己业务对data处理尚未完成或者失败,OOMDetector内部暂时不会删除临时文件 - completionHandler(NO); + if(completionHandler){ + completionHandler(NO); + } } else { - completionHandler(YES); + if(completionHandler){ + completionHandler(YES); + } } } diff --git a/OOMDetector.xcworkspace/xcuserdata/rosen.xcuserdatad/UserInterfaceState.xcuserstate b/OOMDetector.xcworkspace/xcuserdata/rosen.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 67e5c40..0000000 Binary files a/OOMDetector.xcworkspace/xcuserdata/rosen.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/OOMDetector.xcworkspace/xcuserdata/rosen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/OOMDetector.xcworkspace/xcuserdata/rosen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index c0ec046..0000000 --- a/OOMDetector.xcworkspace/xcuserdata/rosen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,646 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/README.md b/README.md index 58c1cd4..08b06a2 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,6 @@ OOMDetector是一个iOS内存监控组件,应用此组件可以帮助你轻松 - 2.大内存分配监控:监控单次大块内存分配,提供分配堆栈信息 - 3.内存泄漏检测:可检测OC对象、Malloc堆内存泄漏,提供泄漏堆栈信息 -## 技术交流 -QQ交流群:565644607 - ## 演示 ![demo_gif](assets/oomgif.gif) diff --git a/libOOMDetector/libOOMDetector.xcodeproj/project.pbxproj b/libOOMDetector/libOOMDetector.xcodeproj/project.pbxproj index 8092ad8..186ad14 100644 --- a/libOOMDetector/libOOMDetector.xcodeproj/project.pbxproj +++ b/libOOMDetector/libOOMDetector.xcodeproj/project.pbxproj @@ -6,25 +6,24 @@ objectVersion = 48; objects = { -/* Begin PBXAggregateTarget section */ - 6B9A04F81FD5839A00414B1F /* libOOMAggregate */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 6B9A04FB1FD5839A00414B1F /* Build configuration list for PBXAggregateTarget "libOOMAggregate" */; - buildPhases = ( - 6B9A04FC1FD583A700414B1F /* ShellScript */, - ); - dependencies = ( - ); - name = libOOMAggregate; - productName = libOOMAggregate; - }; -/* End PBXAggregateTarget section */ - /* Begin PBXBuildFile section */ + 4A212CAA206259D6001960DA /* RapidCRC.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A212CA8206259D6001960DA /* RapidCRC.c */; }; + 4A212CAB206259D6001960DA /* RapidCRC.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A212CA9206259D6001960DA /* RapidCRC.h */; }; + 4A406D35207A18C900CAFBD2 /* CStackHighSpeedLogger.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4A406D33207A18C800CAFBD2 /* CStackHighSpeedLogger.mm */; }; + 4A406D36207A18C900CAFBD2 /* CStackHighSpeedLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A406D34207A18C900CAFBD2 /* CStackHighSpeedLogger.h */; }; + 4A6C2A18209C44FA005CCEE9 /* FOOMMonitor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4A6C2A16209C44FA005CCEE9 /* FOOMMonitor.mm */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; + 4A6C2A19209C44FA005CCEE9 /* FOOMMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A6C2A17209C44FA005CCEE9 /* FOOMMonitor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4A6C2A1C209C5438005CCEE9 /* HighSpeedLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A6C2A1A209C5438005CCEE9 /* HighSpeedLogger.h */; }; + 4A6C2A1D209C5438005CCEE9 /* HighSpeedLogger.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4A6C2A1B209C5438005CCEE9 /* HighSpeedLogger.mm */; }; + 4A6C2A20209C6645005CCEE9 /* NSObject+FOOMSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A6C2A1E209C6645005CCEE9 /* NSObject+FOOMSwizzle.h */; }; + 4A6C2A21209C6645005CCEE9 /* NSObject+FOOMSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A6C2A1F209C6645005CCEE9 /* NSObject+FOOMSwizzle.m */; }; + 4A93E4B0206A1E9A006C0F56 /* CLeakedStacksHashmap.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4A93E4AE206A1E9A006C0F56 /* CLeakedStacksHashmap.mm */; }; + 4A93E4B1206A1E9A006C0F56 /* CLeakedStacksHashmap.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A93E4AF206A1E9A006C0F56 /* CLeakedStacksHashmap.h */; }; 4AA4A0831FF13066009F2921 /* CLeakChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AA4A0811FF13066009F2921 /* CLeakChecker.h */; }; 4AA4A0841FF13066009F2921 /* CLeakChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4AA4A0821FF13066009F2921 /* CLeakChecker.mm */; }; 4AA4A0871FF1F9F6009F2921 /* COOMDetector.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AA4A0851FF1F9F6009F2921 /* COOMDetector.h */; }; 4AA4A0881FF1F9F6009F2921 /* COOMDetector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4AA4A0861FF1F9F6009F2921 /* COOMDetector.mm */; }; + 4AB88A2D22B8909800B44FA9 /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AB88A2C22B8909800B44FA9 /* fishhook.c */; }; 6B9A04671FD57C5700414B1F /* libOOMDetector.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B9A04651FD57C5700414B1F /* libOOMDetector.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6B9A04B91FD57C8A00414B1F /* QQLeakPredefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B9A046F1FD57C8A00414B1F /* QQLeakPredefines.h */; }; 6B9A04BC1FD57C8A00414B1F /* CStackHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B9A04731FD57C8A00414B1F /* CStackHelper.h */; }; @@ -47,8 +46,6 @@ 6B9A04CD1FD57C8A00414B1F /* QQLeakChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B9A04871FD57C8A00414B1F /* QQLeakChecker.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6B9A04CE1FD57C8A00414B1F /* OOMMemoryStackTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B9A048A1FD57C8A00414B1F /* OOMMemoryStackTracker.h */; }; 6B9A04CF1FD57C8A00414B1F /* OOMMemoryStackTracker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6B9A048B1FD57C8A00414B1F /* OOMMemoryStackTracker.mm */; }; - 6B9A04D01FD57C8A00414B1F /* HighSpeedLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B9A048D1FD57C8A00414B1F /* HighSpeedLogger.h */; }; - 6B9A04D11FD57C8A00414B1F /* HighSpeedLogger.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6B9A048E1FD57C8A00414B1F /* HighSpeedLogger.mm */; }; 6B9A04D21FD57C8A00414B1F /* OOMDetector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6B9A04901FD57C8A00414B1F /* OOMDetector.mm */; }; 6B9A04D31FD57C8A00414B1F /* OOMDetectorLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B9A04911FD57C8A00414B1F /* OOMDetectorLogger.h */; }; 6B9A04D41FD57C8A00414B1F /* OOMDetectorLogger.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6B9A04921FD57C8A00414B1F /* OOMDetectorLogger.mm */; }; @@ -56,7 +53,6 @@ 6B9A04D61FD57C8A00414B1F /* MemoryIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B9A04951FD57C8A00414B1F /* MemoryIndicator.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; 6B9A04D71FD57C8A00414B1F /* OOMStatisticsInfoCenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B9A04971FD57C8A00414B1F /* OOMStatisticsInfoCenter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6B9A04D81FD57C8A00414B1F /* OOMStatisticsInfoCenter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6B9A04981FD57C8A00414B1F /* OOMStatisticsInfoCenter.mm */; }; - 6B9A04D91FD57C8A00414B1F /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 6B9A049B1FD57C8A00414B1F /* fishhook.c */; }; 6B9A04DA1FD57C8A00414B1F /* fishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B9A049C1FD57C8A00414B1F /* fishhook.h */; }; 6B9A04DB1FD57C8A00414B1F /* AllocationTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B9A049E1FD57C8A00414B1F /* AllocationTracker.h */; }; 6B9A04DC1FD57C8A00414B1F /* AllocationTracker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6B9A049F1FD57C8A00414B1F /* AllocationTracker.mm */; }; @@ -84,10 +80,25 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 4A212CA8206259D6001960DA /* RapidCRC.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = RapidCRC.c; sourceTree = ""; }; + 4A212CA9206259D6001960DA /* RapidCRC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RapidCRC.h; sourceTree = ""; }; + 4A406D33207A18C800CAFBD2 /* CStackHighSpeedLogger.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CStackHighSpeedLogger.mm; sourceTree = ""; }; + 4A406D34207A18C900CAFBD2 /* CStackHighSpeedLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CStackHighSpeedLogger.h; sourceTree = ""; }; + 4A6C2A16209C44FA005CCEE9 /* FOOMMonitor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FOOMMonitor.mm; sourceTree = ""; }; + 4A6C2A17209C44FA005CCEE9 /* FOOMMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FOOMMonitor.h; path = ../OOMDetector/main/FOOMMonitor.h; sourceTree = ""; }; + 4A6C2A1A209C5438005CCEE9 /* HighSpeedLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HighSpeedLogger.h; sourceTree = ""; }; + 4A6C2A1B209C5438005CCEE9 /* HighSpeedLogger.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HighSpeedLogger.mm; sourceTree = ""; }; + 4A6C2A1E209C6645005CCEE9 /* NSObject+FOOMSwizzle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+FOOMSwizzle.h"; sourceTree = ""; }; + 4A6C2A1F209C6645005CCEE9 /* NSObject+FOOMSwizzle.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+FOOMSwizzle.m"; sourceTree = ""; }; + 4A93E4AE206A1E9A006C0F56 /* CLeakedStacksHashmap.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CLeakedStacksHashmap.mm; sourceTree = ""; }; + 4A93E4AF206A1E9A006C0F56 /* CLeakedStacksHashmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CLeakedStacksHashmap.h; sourceTree = ""; }; + 4A9C1E332084557900E54134 /* libOOMDetector copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "libOOMDetector copy-Info.plist"; path = "/Users/rosen/Desktop/Application/QQLeak/OOMDetector/libOOMDetector/libOOMDetector copy-Info.plist"; sourceTree = ""; }; 4AA4A0811FF13066009F2921 /* CLeakChecker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CLeakChecker.h; sourceTree = ""; }; 4AA4A0821FF13066009F2921 /* CLeakChecker.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CLeakChecker.mm; sourceTree = ""; }; 4AA4A0851FF1F9F6009F2921 /* COOMDetector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COOMDetector.h; sourceTree = ""; }; 4AA4A0861FF1F9F6009F2921 /* COOMDetector.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = COOMDetector.mm; sourceTree = ""; }; + 4AB88A2C22B8909800B44FA9 /* fishhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fishhook.c; sourceTree = ""; }; + 4AD45263206130AA00116ED9 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 6B9A04621FD57C5700414B1F /* libOOMDetector.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = libOOMDetector.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6B9A04651FD57C5700414B1F /* libOOMDetector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = libOOMDetector.h; sourceTree = ""; }; 6B9A04661FD57C5700414B1F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -112,8 +123,6 @@ 6B9A04871FD57C8A00414B1F /* QQLeakChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QQLeakChecker.h; sourceTree = ""; }; 6B9A048A1FD57C8A00414B1F /* OOMMemoryStackTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOMMemoryStackTracker.h; sourceTree = ""; }; 6B9A048B1FD57C8A00414B1F /* OOMMemoryStackTracker.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OOMMemoryStackTracker.mm; sourceTree = ""; }; - 6B9A048D1FD57C8A00414B1F /* HighSpeedLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HighSpeedLogger.h; sourceTree = ""; }; - 6B9A048E1FD57C8A00414B1F /* HighSpeedLogger.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HighSpeedLogger.mm; sourceTree = ""; }; 6B9A04901FD57C8A00414B1F /* OOMDetector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OOMDetector.mm; sourceTree = ""; }; 6B9A04911FD57C8A00414B1F /* OOMDetectorLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOMDetectorLogger.h; sourceTree = ""; }; 6B9A04921FD57C8A00414B1F /* OOMDetectorLogger.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OOMDetectorLogger.mm; sourceTree = ""; }; @@ -121,7 +130,6 @@ 6B9A04951FD57C8A00414B1F /* MemoryIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MemoryIndicator.m; sourceTree = ""; }; 6B9A04971FD57C8A00414B1F /* OOMStatisticsInfoCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOMStatisticsInfoCenter.h; sourceTree = ""; }; 6B9A04981FD57C8A00414B1F /* OOMStatisticsInfoCenter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OOMStatisticsInfoCenter.mm; sourceTree = ""; }; - 6B9A049B1FD57C8A00414B1F /* fishhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fishhook.c; sourceTree = ""; }; 6B9A049C1FD57C8A00414B1F /* fishhook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fishhook.h; sourceTree = ""; }; 6B9A049E1FD57C8A00414B1F /* AllocationTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AllocationTracker.h; sourceTree = ""; }; 6B9A049F1FD57C8A00414B1F /* AllocationTracker.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AllocationTracker.mm; sourceTree = ""; }; @@ -159,11 +167,21 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 4AD45262206130A700116ED9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4AD45263206130AA00116ED9 /* libz.tbd */, + ); + name = Frameworks; + sourceTree = ""; + }; 6B9A04581FD57C5700414B1F = { isa = PBXGroup; children = ( 6B9A04641FD57C5700414B1F /* libOOMDetector */, 6B9A04631FD57C5700414B1F /* Products */, + 4AD45262206130A700116ED9 /* Frameworks */, + 4A9C1E332084557900E54134 /* libOOMDetector copy-Info.plist */, ); sourceTree = ""; }; @@ -210,6 +228,8 @@ 6B9A04701FD57C8A00414B1F /* stack */ = { isa = PBXGroup; children = ( + 4A212CA8206259D6001960DA /* RapidCRC.c */, + 4A212CA9206259D6001960DA /* RapidCRC.h */, 6B9A04731FD57C8A00414B1F /* CStackHelper.h */, 6B9A04741FD57C8A00414B1F /* CStackHelper.mm */, 6B9A04751FD57C8A00414B1F /* CommonMallocLogger.h */, @@ -221,6 +241,8 @@ 6B9A04771FD57C8A00414B1F /* structure */ = { isa = PBXGroup; children = ( + 4A406D34207A18C900CAFBD2 /* CStackHighSpeedLogger.h */, + 4A406D33207A18C800CAFBD2 /* CStackHighSpeedLogger.mm */, 6B9A04781FD57C8A00414B1F /* CBaseHashmap.h */, 6B9A04791FD57C8A00414B1F /* CBaseHashmap.mm */, 6B9A047A1FD57C8A00414B1F /* CPtrsHashmap.h */, @@ -248,6 +270,7 @@ isa = PBXGroup; children = ( 6B9A04861FD57C8A00414B1F /* OOMDetector.h */, + 4A6C2A17209C44FA005CCEE9 /* FOOMMonitor.h */, 6B9A04871FD57C8A00414B1F /* QQLeakChecker.h */, ); path = Headers; @@ -277,8 +300,6 @@ 6B9A048C1FD57C8A00414B1F /* logger */ = { isa = PBXGroup; children = ( - 6B9A048D1FD57C8A00414B1F /* HighSpeedLogger.h */, - 6B9A048E1FD57C8A00414B1F /* HighSpeedLogger.mm */, 6B9A04911FD57C8A00414B1F /* OOMDetectorLogger.h */, 6B9A04921FD57C8A00414B1F /* OOMDetectorLogger.mm */, ); @@ -288,6 +309,9 @@ 6B9A048F1FD57C8A00414B1F /* main */ = { isa = PBXGroup; children = ( + 4A6C2A1A209C5438005CCEE9 /* HighSpeedLogger.h */, + 4A6C2A1B209C5438005CCEE9 /* HighSpeedLogger.mm */, + 4A6C2A16209C44FA005CCEE9 /* FOOMMonitor.mm */, 6B9A04901FD57C8A00414B1F /* OOMDetector.mm */, 4AA4A0851FF1F9F6009F2921 /* COOMDetector.h */, 4AA4A0861FF1F9F6009F2921 /* COOMDetector.mm */, @@ -329,7 +353,7 @@ 6B9A049A1FD57C8A00414B1F /* extern */ = { isa = PBXGroup; children = ( - 6B9A049B1FD57C8A00414B1F /* fishhook.c */, + 4AB88A2C22B8909800B44FA9 /* fishhook.c */, 6B9A049C1FD57C8A00414B1F /* fishhook.h */, ); path = extern; @@ -342,6 +366,8 @@ 6B9A049F1FD57C8A00414B1F /* AllocationTracker.mm */, 6B9A04A01FD57C8A00414B1F /* CMallocHook.h */, 6B9A04A11FD57C8A00414B1F /* CMallocHook.mm */, + 4A6C2A1E209C6645005CCEE9 /* NSObject+FOOMSwizzle.h */, + 4A6C2A1F209C6645005CCEE9 /* NSObject+FOOMSwizzle.m */, ); path = hook; sourceTree = ""; @@ -387,6 +413,8 @@ 6B9A04B41FD57C8A00414B1F /* structures */ = { isa = PBXGroup; children = ( + 4A93E4AF206A1E9A006C0F56 /* CLeakedStacksHashmap.h */, + 4A93E4AE206A1E9A006C0F56 /* CLeakedStacksHashmap.mm */, 6B9A04B51FD57C8A00414B1F /* CLeakedHashmap.h */, 6B9A04B61FD57C8A00414B1F /* CLeakedHashmap.mm */, 6B9A04B71FD57C8A00414B1F /* CThreadTrackingHashmap.h */, @@ -404,25 +432,29 @@ files = ( 6B9A04E61FD57C8A00414B1F /* CRegisterChecker.h in Headers */, 6B9A04CA1FD57C8A00414B1F /* QQLeakFileUploadCenter.h in Headers */, + 4A6C2A19209C44FA005CCEE9 /* FOOMMonitor.h in Headers */, 6B9A04CD1FD57C8A00414B1F /* QQLeakChecker.h in Headers */, 6B9A04CC1FD57C8A00414B1F /* OOMDetector.h in Headers */, + 6B9A04671FD57C5700414B1F /* libOOMDetector.h in Headers */, 6B9A04D71FD57C8A00414B1F /* OOMStatisticsInfoCenter.h in Headers */, 6B9A04C61FD57C8A00414B1F /* QQLeakDataUploadCenter.h in Headers */, + 4A212CAB206259D6001960DA /* RapidCRC.h in Headers */, 6B9A04D51FD57C8A00414B1F /* MemoryIndicator.h in Headers */, 6B9A04B91FD57C8A00414B1F /* QQLeakPredefines.h in Headers */, 6B9A04E01FD57C8A00414B1F /* QQLeakMallocStackTracker.h in Headers */, 6B9A04E41FD57C8A00414B1F /* CMemoryChecker.h in Headers */, 6B9A04F01FD57C8A00414B1F /* CThreadTrackingHashmap.h in Headers */, + 4A406D36207A18C900CAFBD2 /* CStackHighSpeedLogger.h in Headers */, 4AA4A0871FF1F9F6009F2921 /* COOMDetector.h in Headers */, 6B9A04CE1FD57C8A00414B1F /* OOMMemoryStackTracker.h in Headers */, 6B9A04C01FD57C8A00414B1F /* CBaseHashmap.h in Headers */, + 4A6C2A1C209C5438005CCEE9 /* HighSpeedLogger.h in Headers */, 6B9A04EC1FD57C8A00414B1F /* CObjcFilter.h in Headers */, - 6B9A04671FD57C5700414B1F /* libOOMDetector.h in Headers */, - 6B9A04D01FD57C8A00414B1F /* HighSpeedLogger.h in Headers */, 6B9A04C41FD57C8A00414B1F /* CStacksHashmap.h in Headers */, 6B9A04BC1FD57C8A00414B1F /* CStackHelper.h in Headers */, 6B9A04E21FD57C8A00414B1F /* CHeapChecker.h in Headers */, 6B9A04C21FD57C8A00414B1F /* CPtrsHashmap.h in Headers */, + 4A6C2A20209C6645005CCEE9 /* NSObject+FOOMSwizzle.h in Headers */, 4AA4A0831FF13066009F2921 /* CLeakChecker.h in Headers */, 6B9A04EE1FD57C8A00414B1F /* CLeakedHashmap.h in Headers */, 6B9A04DA1FD57C8A00414B1F /* fishhook.h in Headers */, @@ -431,6 +463,7 @@ 6B9A04E81FD57C8A00414B1F /* CSegmentChecker.h in Headers */, 6B9A04C81FD57C8A00414B1F /* QQLeakDeviceInfo.h in Headers */, 6B9A04EA1FD57C8A00414B1F /* CStackChecker.h in Headers */, + 4A93E4B1206A1E9A006C0F56 /* CLeakedStacksHashmap.h in Headers */, 6B9A04DD1FD57C8A00414B1F /* CMallocHook.h in Headers */, 6B9A04DB1FD57C8A00414B1F /* AllocationTracker.h in Headers */, ); @@ -469,10 +502,6 @@ CreatedOnToolsVersion = 9.1; ProvisioningStyle = Automatic; }; - 6B9A04F81FD5839A00414B1F = { - CreatedOnToolsVersion = 9.1; - ProvisioningStyle = Automatic; - }; }; }; buildConfigurationList = 6B9A045C1FD57C5700414B1F /* Build configuration list for PBXProject "libOOMDetector" */; @@ -488,7 +517,6 @@ projectRoot = ""; targets = ( 6B9A04611FD57C5700414B1F /* libOOMDetector */, - 6B9A04F81FD5839A00414B1F /* libOOMAggregate */, ); }; /* End PBXProject section */ @@ -503,22 +531,6 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 6B9A04FC1FD583A700414B1F /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if [ \"${ACTION}\" = \"build\" ]\nthen\nINSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}.framework\n\nDEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework\n\nSIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework\n\n\nif [ -d \"${INSTALL_DIR}\" ]\nthen\nrm -rf \"${INSTALL_DIR}\"\nfi\n\nmkdir -p \"${INSTALL_DIR}\"\n\ncp -R \"${DEVICE_DIR}/\" \"${INSTALL_DIR}/\"\n#ditto \"${DEVICE_DIR}/Headers\" \"${INSTALL_DIR}/Headers\"\n\nlipo -create \"${DEVICE_DIR}/${PROJECT_NAME}\" \"${SIMULATOR_DIR}/${PROJECT_NAME}\" -output \"${DEVICE_DIR}/${PROJECT_NAME}\"\n\n#open \"${DEVICE_DIR}\"\n#open \"${SRCROOT}/Products\"\nfi"; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 6B9A045D1FD57C5700414B1F /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -526,6 +538,7 @@ files = ( 6B9A04E51FD57C8A00414B1F /* CMemoryChecker.mm in Sources */, 6B9A04C91FD57C8A00414B1F /* QQLeakDeviceInfo.m in Sources */, + 4AB88A2D22B8909800B44FA9 /* fishhook.c in Sources */, 6B9A04E11FD57C8A00414B1F /* QQLeakMallocStackTracker.mm in Sources */, 6B9A04C31FD57C8A00414B1F /* CPtrsHashmap.mm in Sources */, 6B9A04EF1FD57C8A00414B1F /* CLeakedHashmap.mm in Sources */, @@ -533,24 +546,28 @@ 6B9A04E71FD57C8A00414B1F /* CRegisterChecker.mm in Sources */, 6B9A04E31FD57C8A00414B1F /* CHeapChecker.mm in Sources */, 6B9A04DE1FD57C8A00414B1F /* CMallocHook.mm in Sources */, + 4A212CAA206259D6001960DA /* RapidCRC.c in Sources */, + 4A406D35207A18C900CAFBD2 /* CStackHighSpeedLogger.mm in Sources */, 6B9A04BD1FD57C8A00414B1F /* CStackHelper.mm in Sources */, 6B9A04F11FD57C8A00414B1F /* CThreadTrackingHashmap.mm in Sources */, + 4A6C2A21209C6645005CCEE9 /* NSObject+FOOMSwizzle.m in Sources */, 6B9A04D21FD57C8A00414B1F /* OOMDetector.mm in Sources */, 6B9A04BF1FD57C8A00414B1F /* CommonMallocLogger.mm in Sources */, + 4A6C2A18209C44FA005CCEE9 /* FOOMMonitor.mm in Sources */, 4AA4A0841FF13066009F2921 /* CLeakChecker.mm in Sources */, 6B9A04D81FD57C8A00414B1F /* OOMStatisticsInfoCenter.mm in Sources */, 6B9A04ED1FD57C8A00414B1F /* CObjcFilter.mm in Sources */, + 4A93E4B0206A1E9A006C0F56 /* CLeakedStacksHashmap.mm in Sources */, 6B9A04DC1FD57C8A00414B1F /* AllocationTracker.mm in Sources */, - 6B9A04D91FD57C8A00414B1F /* fishhook.c in Sources */, 6B9A04C51FD57C8A00414B1F /* CStacksHashmap.mm in Sources */, 6B9A04CB1FD57C8A00414B1F /* QQLeakFileUploadCenter.mm in Sources */, 6B9A04CF1FD57C8A00414B1F /* OOMMemoryStackTracker.mm in Sources */, 6B9A04D41FD57C8A00414B1F /* OOMDetectorLogger.mm in Sources */, - 6B9A04D11FD57C8A00414B1F /* HighSpeedLogger.mm in Sources */, 6B9A04C71FD57C8A00414B1F /* QQLeakDataUploadCenter.mm in Sources */, 6B9A04EB1FD57C8A00414B1F /* CStackChecker.mm in Sources */, 6B9A04D61FD57C8A00414B1F /* MemoryIndicator.m in Sources */, 6B9A04E91FD57C8A00414B1F /* CSegmentChecker.mm in Sources */, + 4A6C2A1D209C5438005CCEE9 /* HighSpeedLogger.mm in Sources */, 6B9A04C11FD57C8A00414B1F /* CBaseHashmap.mm in Sources */, 6B9A04DF1FD57C8A00414B1F /* QQLeakChecker.mm in Sources */, ); @@ -682,7 +699,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = libOOMDetector/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LINK_WITH_STANDARD_LIBRARIES = YES; MACH_O_TYPE = staticlib; @@ -709,7 +726,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = libOOMDetector/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LINK_WITH_STANDARD_LIBRARIES = YES; MACH_O_TYPE = staticlib; @@ -723,22 +740,6 @@ }; name = Release; }; - 6B9A04F91FD5839A00414B1F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 6B9A04FA1FD5839A00414B1F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -760,15 +761,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 6B9A04FB1FD5839A00414B1F /* Build configuration list for PBXAggregateTarget "libOOMAggregate" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6B9A04F91FD5839A00414B1F /* Debug */, - 6B9A04FA1FD5839A00414B1F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = 6B9A04591FD57C5700414B1F /* Project object */; diff --git a/libOOMDetector/libOOMDetector.xcodeproj/xcuserdata/rosen.xcuserdatad/xcschemes/xcschememanagement.plist b/libOOMDetector/libOOMDetector.xcodeproj/xcuserdata/rosen.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 10bef66..0000000 --- a/libOOMDetector/libOOMDetector.xcodeproj/xcuserdata/rosen.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,19 +0,0 @@ - - - - - SchemeUserState - - libOOMAggregate.xcscheme - - orderHint - 2 - - libOOMDetector.xcscheme - - orderHint - 0 - - - - diff --git a/libOOMDetector/libOOMDetector/OOMDetector/.DS_Store b/libOOMDetector/libOOMDetector/OOMDetector/.DS_Store deleted file mode 100644 index 45f4ec0..0000000 Binary files a/libOOMDetector/libOOMDetector/OOMDetector/.DS_Store and /dev/null differ diff --git a/libOOMDetector/libOOMDetector/OOMDetector/Headers/OOMDetector.h b/libOOMDetector/libOOMDetector/OOMDetector/Headers/OOMDetector.h index 5857ee3..01952cd 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/Headers/OOMDetector.h +++ b/libOOMDetector/libOOMDetector/OOMDetector/Headers/OOMDetector.h @@ -1,6 +1,6 @@ // // OOMDetector.h -// QQLeak +// libOOMDetector // // Tencent is pleased to support the open source community by making OOMDetector available. // Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. @@ -15,10 +15,6 @@ // and limitations under the License. // // -// version:1.4 -// 增加log回调,修复vmlogger为空时的crash -// 屏蔽私有API -// #ifndef OOMDetector_h #define OOMDetector_h @@ -62,6 +58,12 @@ typedef void (^ChunkMallocBlock)(size_t bytes, NSString *stack); */ -(void)startMaxMemoryStatistic:(double)overFlowLimit; +/*! @brief 注册SDK内部日志回调,用于输出SDK内部日志 + * + * @param logger 外部的日志打印方法 + */ +-(void)registerLogCallback:(logCallback)logger; + /** 在调用startMaxMemoryStatistic:开启内存触顶监控后会触发此回调,返回前一次app运行时单次生命周期内的最大物理内存数据 */ -(void)setPerformanceDataDelegate:(id)delegate; @@ -115,22 +117,35 @@ typedef void (^ChunkMallocBlock)(size_t bytes, NSString *stack); /** 日志打印回调block */ @property (nonatomic, copy) LogPrintBlock logPrintBlock; -/*! @brief 开始堆内存堆栈监控,成功则返回YES - 1.有一定性能开销,建议增加控制策略选择性打开 - 2.该功能开启后会实时记录所有的内存分配堆栈,并将多次重复调用的相同堆栈合并,如果合并后的size大于threshHoldInbytes,该分配堆栈将被输出到log用于分析,log路径Library/OOMDetector +/*! @brief 开始堆内存堆栈监控,成功则返回YES(会增加8%左右的cpu开销和10Mb内存,建议抽样开启) * @param threshholdInBytes 堆内存阈值(bytes) - * @param needAutoDump 如果设置为YES,当app占用的内存超过dumpLimit时,自动执行dump堆栈操作 - * @param dumpLimit 只有needAutoDump设置为YES,app占用的内存超过dumpLimit(Mb)时,自动执行dump堆栈操作 - * @param sampleInterval 检测内存的间隔(单位s),一般情况下此值设为0.1即可 + * @param uuid 用于唯一标识输出的堆栈日志 */ --(BOOL)startMallocStackMonitor:(size_t)threshholdInBytes needAutoDumpWhenOverflow:(BOOL)needAutoDump dumpLimit:(double)dumpLimit sampleInterval:(NSTimeInterval)sampleInterval; +-(BOOL)startMallocStackMonitor:(size_t)threshholdInBytes logUUID:(NSString *)uuid; + +/*! @brief 设置堆内存监控抽样因子,用于对小块内存抽样监控 + + * @param factor 如factor=1/10,则按照1/10抽样 + */ +-(void)setMallocSampleFactor:(uint32_t)factor; + +/*! @brief 设置不进行抽样的内存阀值(bytes) + + * @param sampleThreshhold 如sampleThreshhold=1024*1024,则超过1Mb的内存分配不进行抽样 + */ +-(void)setMallocNoSampleThreshold:(uint32_t)sampleThreshhold; /*! @brief 关闭堆内存堆栈监控 * */ -(void)stopMallocStackMonitor; +/*! @brief 设置系统的私有API __syscall_logger,因为__syscall_logger是系统私有API,该功能不要在appstore版本打开 + * + */ +-(void)setVMLogger:(void**)logger; + /*! @brief 开始VM内存堆栈监控,成功则返回YES(有一定性能开销,建议增加控制策略选择性打开)。 * 因为startVMStackMonitor:方法用到了私有API __syscall_logger会带来app store审核不通过的风险,此方法默认只在DEBUG模式下生效,如果 * 需要在RELEASE模式下也可用,请打开USE_VM_LOGGER_FORCEDLY宏,但是切记在提交appstore前将此宏关闭,否则可能会审核不通过 @@ -139,23 +154,13 @@ typedef void (^ChunkMallocBlock)(size_t bytes, NSString *stack); */ //#define USE_VM_LOGGER_FORCEDLY --(BOOL)startVMStackMonitor:(size_t)threshHoldInbytes; +-(BOOL)startVMStackMonitor:(size_t)threshHoldInbytes logUUID:(NSString *)uuid; /*! @brief 关闭堆内存监控 * */ -(void)stopVMStackMonitor; -/*! @brief 立即将内存中纪录的分配堆栈信息写入磁盘,当前log路径可通过currentStackLogDir获取 - * 说明:当需要立即纪录当前内存中的分配信息时候调用 - */ --(void)flush_allocation_stack; - -/*! @brief 调用该接口上报所有缓存的OOM相关log给通过setFileDataDelegate:方法设置的代理,建议在启动的时候调用 - * 说明:dump数据存储在Library/OOMDetector目录中,上报成功后自动删除 - */ --(void)uploadAllStack; - /*! @brief 设置输出的log中的最大堆栈深度 * */ @@ -178,8 +183,32 @@ typedef void (^ChunkMallocBlock)(size_t bytes, NSString *stack); */ -(NSString *)currentStackLogDir; +/*! @brief 根据uuid获取上一次的OOM数据 + * + */ +-(NSArray *)getOOMDataByUUID:(NSString *)uuid; + +/*! @brief 当记录的堆栈超过一定数量限制时候是否需要清理(默认清理,maxNum=300000,minimumStackSize=1024000bytes) + * +* @param isNeed YES表示需要清理 +* @param maxNum 当记录的总堆栈个数超过maxNum时自动清理低于mininumSize的堆栈 +* @param mininumSize 低于mininumSize的堆栈将被清理 + */ +-(void)setNeedCleanStack:(BOOL)isNeed maxStackNum:(size_t)maxNum minimumStackSize:(size_t)mininumSize; + +/*! @brief 清空磁盘中的OOM堆栈日志 + * + */ +-(void)clearOOMLog; + +/*! @brief 获取工具占用内存(Mb) + * + */ +-(double)getOccupyMemory; + @property (nonatomic, copy) ChunkMallocBlock chunkMallocBlock; + @end #endif /* OOMDetector_h */ diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/.DS_Store b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/.DS_Store deleted file mode 100644 index 6dc9fe0..0000000 Binary files a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/.DS_Store and /dev/null differ diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/logger/HighSpeedLogger.h b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/logger/HighSpeedLogger.h index 1c41399..eac1ea3 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/logger/HighSpeedLogger.h +++ b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/logger/HighSpeedLogger.h @@ -30,6 +30,7 @@ class HighSpeedLogger ~HighSpeedLogger(); HighSpeedLogger(malloc_zone_t *zone, NSString *path, size_t mmap_size); BOOL sprintfLogger(size_t grain_size,const char *format, ...); + size_t memcpyLogger(const char *content, size_t length); void cleanLogger(); void syncLogger(); bool isValid(); diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/logger/HighSpeedLogger.mm b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/logger/HighSpeedLogger.mm index f2ddcf2..fbc013e 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/logger/HighSpeedLogger.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/logger/HighSpeedLogger.mm @@ -35,6 +35,7 @@ current_len = 0; mmap_size = size; memory_zone = zone; + isFailed = false; FILE *fp = fopen ( [path fileSystemRepresentation] , "wb+" ) ; if(fp != NULL){ int ret = ftruncate(fileno(fp), size); @@ -110,6 +111,49 @@ return result; } +size_t HighSpeedLogger::memcpyLogger(const char *content, size_t length) +{ + size_t result = 0; + if(isFailed){ + return result; + } + if(length + current_len < mmap_size - 1){ + memcpy(mmap_ptr + current_len, content, length); + result = current_len; + current_len += length; + return current_len; + } + else { + char *copy = (char *)memory_zone->malloc(memory_zone, mmap_size); + memcpy(copy, mmap_ptr, mmap_size); + size_t copy_size = mmap_size; + munmap(mmap_ptr ,mmap_size); + mmap_size = current_len + length; + int ret = ftruncate(fileno(mmap_fp), mmap_size); + if(ret == -1){ + memory_zone->free(memory_zone,copy); + return result; + } + else { + fseek(mmap_fp, 0, SEEK_SET); + mmap_ptr = (char *)mmap(0, mmap_size, PROT_WRITE | PROT_READ, (MAP_FILE|MAP_SHARED), fileno(mmap_fp), 0); + memset(mmap_ptr, '\0', mmap_size); + if(!mmap_ptr){ + memory_zone->free(memory_zone,copy); + return result; + } + else { + memcpy(mmap_ptr, copy, copy_size); + memcpy(mmap_ptr + current_len, content, length); + result = current_len; + current_len += length; + } + } + memory_zone->free(memory_zone,copy); + } + return result; +} + void HighSpeedLogger::cleanLogger() { current_len = 0; diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/COOMDetector.h b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/COOMDetector.h index 2705847..46f3caf 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/COOMDetector.h +++ b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/COOMDetector.h @@ -14,7 +14,6 @@ #import "stdio.h" #import "OOMMemoryStackTracker.h" #import "QQLeakPredefines.h" -#import "HighSpeedLogger.h" #import "CStackHelper.h" #import "OOMDetector.h" #import "CStacksHashmap.h" @@ -25,18 +24,27 @@ #import "CStackHelper.h" #import "CommonMallocLogger.h" #import +#import +#import + +typedef void (*LogPrinter)(char *log); + +typedef enum{ + Malloc_Type, + VM_Type +}malloc_type; class COOMDetector { public: COOMDetector(); ~COOMDetector(); - void recordVMStack(vm_address_t address,uint32_t size,const char*type,size_t stack_num_to_skip); + void recordMallocStack(vm_address_t address,uint32_t size,size_t stack_num_to_skip); + void removeMallocStack(vm_address_t address); + void recordVMStack(vm_address_t address,uint32_t size,size_t stack_num_to_skip); void removeVMStack(vm_address_t address); - void recordMallocStack(vm_address_t address,uint32_t size,const char*name,size_t stack_num_to_skip); - void removeMallocStack(vm_address_t address,monitor_mode mode); - void flush_allocation_stack(); - void initLogger(malloc_zone_t *zone, NSString *path, size_t mmap_size,LogPrinter printer); + void initLogger(malloc_zone_t *zone, NSString *path, size_t mmap_size); + void initVMLogger(malloc_zone_t *zone, NSString *path, size_t mmap_size); BOOL startMallocStackMonitor(size_t threshholdInBytes); void stopMallocStackMonitor(); BOOL startVMStackMonitor(size_t threshholdInBytes); @@ -48,34 +56,46 @@ class COOMDetector malloc_zone_t *getMemoryZone(); CPtrsHashmap *getPtrHashmap(); CStacksHashmap *getStackHashmap(); - HighSpeedLogger *getStackLogger(); public: - size_t max_stack_depth; + size_t max_stack_depth = 64; BOOL needSysStack = YES; BOOL enableOOMMonitor = NO; BOOL enableChunkMonitor = NO; BOOL enableVMMonitor = NO; - BOOL needStackWithoutAppStack = NO; + BOOL needStackWithoutAppStack = YES; size_t oom_threshold; size_t chunk_threshold; size_t vm_threshold; + BOOL needCleanStackCache = YES; + size_t cache_clean_threshold = 1024*1000; + size_t cache_clean_num = 300000; + bool use_unfair_lock = false; + uint32_t sampleFactor = 1; + uint32_t sampleThreshold = 1024*3; public: malloc_logger_t** vm_sys_logger = NULL; -private: +public: NSString* chunkDataZipPath(); void lockHashmap(); void unlockHashmap(); - void lockVMHashmap(); - void unlockVMHashmap(); private: - CPtrsHashmap *vm_ptrs_hashmap; - CStacksHashmap *vm_stacks_hashmap; + void removeTinyMallocStacks(size_t threshold); +private: CPtrsHashmap *oom_ptrs_hashmap; CStacksHashmap *oom_stacks_hashmap; - HighSpeedLogger *normal_stack_logger = NULL; + CPtrsHashmap *oom_vm_ptrs_hashmap; + CStacksHashmap *oom_vm_stacks_hashmap; ChunkMallocBlock chunkMallocCallback = NULL; CStackHelper *stackHelper = NULL; - pthread_mutex_t hashmap_mutex; - pthread_mutex_t vm_hashmap_mutex; + CStackHelper *chunk_stackHelper = NULL; + QQLeakFileUploadCenter *fileUploadCenter = nil; + NSString *log_path; + size_t log_mmap_size; + NSString *vm_log_path; + size_t vm_log_mmap_size; + os_unfair_lock hashmap_unfair_lock = OS_UNFAIR_LOCK_INIT; + dispatch_semaphore_t hashmap_sema; + os_unfair_lock vm_hashmap_unfair_lock = OS_UNFAIR_LOCK_INIT; + dispatch_semaphore_t vm_hashmap_sema; }; diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/COOMDetector.mm b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/COOMDetector.mm index acf5cc3..6318acd 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/COOMDetector.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/COOMDetector.mm @@ -17,15 +17,67 @@ // and limitations under the License. #import "COOMDetector.h" +#import "fishhook.h" +#import -static size_t grained_size = 512*1024; -//extern malloc_logger_t** vm_sys_logger; +#define do_lockHashmap \ + if(use_unfair_lock){ \ + os_unfair_lock_lock(&hashmap_unfair_lock); \ + } \ + else { \ + dispatch_semaphore_wait(hashmap_sema, DISPATCH_TIME_FOREVER); \ + } -COOMDetector::~COOMDetector() +#define do_unlockHashmap \ + if(use_unfair_lock){ \ + os_unfair_lock_unlock(&hashmap_unfair_lock); \ + } \ + else { \ + dispatch_semaphore_signal(hashmap_sema);\ + } + +#define do_lockVMHashmap \ +if(use_unfair_lock){ \ +os_unfair_lock_lock(&vm_hashmap_unfair_lock); \ +} \ +else { \ +dispatch_semaphore_wait(vm_hashmap_sema, DISPATCH_TIME_FOREVER); \ +} + +#define do_unlockVMHashmap \ +if(use_unfair_lock){ \ +os_unfair_lock_unlock(&vm_hashmap_unfair_lock); \ +} \ +else { \ +dispatch_semaphore_signal(vm_hashmap_sema);\ +} + +extern COOMDetector* global_oomdetector; + +static void* (*orig_mmap)(void *, size_t, int, int, int, off_t); +static int (*orig_munmap)(void *, size_t); + +//static void* orig_mmap = NULL; +//static void* orig_munmap = NULL; + +void *new_mmap(void *dest, size_t size, int author, int type, int fp, off_t offset) { - if(normal_stack_logger != NULL){ - delete normal_stack_logger; + void *ptr = ((void *(*)(void *, size_t, int, int, int, off_t))orig_mmap)(dest, size, author, type, fp, offset); + if(ptr != NULL && (author & 0x2) != 0){ + global_oomdetector->recordVMStack(vm_address_t(dest), uint32_t(size),2); } + return ptr; +} + +int new_munmap(void *dest, size_t size) +{ + int result = ((int(*)(void *, size_t))orig_munmap)(dest,size); + global_oomdetector->removeVMStack(vm_address_t(dest)); + return result; +} + +COOMDetector::~COOMDetector() +{ if(stackHelper != NULL){ delete stackHelper; } @@ -33,11 +85,14 @@ COOMDetector::COOMDetector() { - stackHelper = new CStackHelper(); - pthread_mutex_init(&hashmap_mutex,NULL); - hashmap_mutex = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_init(&vm_hashmap_mutex,NULL); - vm_hashmap_mutex = PTHREAD_MUTEX_INITIALIZER; + //ios10以上使用安全的unfair lock,ios10以下由于spinlock的系统bug,存在一定概率线程优先级反转问题,可能会引发卡死,建议ios10以下系统谨慎使用 + if(@available(iOS 10.0,*)){ + use_unfair_lock = true; + } + else { + hashmap_sema = dispatch_semaphore_create(1); + vm_hashmap_sema = dispatch_semaphore_create(1); + } } NSString *COOMDetector::chunkDataZipPath() @@ -66,18 +121,18 @@ for(size_t j = 2; j < depth; j++){ vm_address_t addr = (vm_address_t)stacks[j]; segImageInfo segImage; - if(stackHelper->getImageByAddr(addr, &segImage)){ + if(chunk_stackHelper->getImageByAddr(addr, &segImage)){ [stackInfo appendFormat:@"\"%lu %s 0x%lx 0x%lx\" ",j - 2,(segImage.name != NULL) ? segImage.name : "unknown",segImage.loadAddr,(long)addr]; } } [stackInfo appendFormat:@"\n"]; - if ([QQLeakFileUploadCenter defaultCenter].fileDataDelegate) { + if (fileUploadCenter.fileDataDelegate) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData *data = [stackInfo dataUsingEncoding:NSUTF8StringEncoding]; if (data && data.length > 0) { NSDictionary *extra = [NSDictionary dictionaryWithObjectsAndKeys:[[UIDevice currentDevice] systemVersion],@"systemversion",[QQLeakDeviceInfo platform],@"Device",@"chunk_malloc",@"type",nil]; - [[QQLeakFileUploadCenter defaultCenter] fileData:data extra:extra type:QQStackReportTypeChunkMemory completionHandler:^(BOOL completed) { + [fileUploadCenter fileData:data extra:extra type:QQStackReportTypeChunkMemory completionHandler:^(BOOL completed) { }]; } @@ -92,210 +147,163 @@ void COOMDetector::lockHashmap() { - pthread_mutex_lock(&hashmap_mutex); + do_lockHashmap } void COOMDetector::unlockHashmap() { - pthread_mutex_unlock(&hashmap_mutex); + do_unlockHashmap } -void COOMDetector::lockVMHashmap() -{ - pthread_mutex_lock(&vm_hashmap_mutex); -} - -void COOMDetector::unlockVMHashmap() -{ - pthread_mutex_unlock(&vm_hashmap_mutex); -} - -void COOMDetector::recordVMStack(vm_address_t address,uint32_t size,const char*type,size_t stack_num_to_skip) +void COOMDetector::recordMallocStack(vm_address_t address,uint32_t size,size_t stack_num_to_skip) { base_stack_t base_stack; base_ptr_log base_ptr; - unsigned char md5[16]; + uint64_t digest; vm_address_t *stack[max_stack_depth]; if(needStackWithoutAppStack){ - base_stack.depth = stackHelper->recordBacktrace(needSysStack,0,stack_num_to_skip, stack,md5,max_stack_depth); + base_stack.depth = (uint32_t)stackHelper->recordBacktrace(needSysStack,0,0,stack_num_to_skip, stack,&digest,max_stack_depth); } else { - base_stack.depth = stackHelper->recordBacktrace(needSysStack,1,stack_num_to_skip, stack,md5,max_stack_depth); + base_stack.depth = (uint32_t)stackHelper->recordBacktrace(needSysStack,0,1,stack_num_to_skip, stack,&digest,max_stack_depth); } if(base_stack.depth > 0){ + base_stack.type = 0; + if(sampleFactor > 1 && size < sampleThreshold){ + base_stack.size = size * sampleFactor; + base_stack.count = sampleFactor; + } + else { + base_stack.size = size; + base_stack.count = 1; + } base_stack.stack = stack; - base_stack.extra.size = size; - base_stack.extra.name = type; - base_ptr.md5 = md5; + base_ptr.digest = digest; base_ptr.size = size; - lockVMHashmap(); - if(vm_ptrs_hashmap && vm_stacks_hashmap){ - if(vm_ptrs_hashmap->insertPtr(address, &base_ptr)){ - vm_stacks_hashmap->insertStackAndIncreaseCountIfExist(md5, &base_stack); + do_lockHashmap + if(oom_ptrs_hashmap && oom_stacks_hashmap){ + if(oom_ptrs_hashmap->insertPtr(address, &base_ptr)){ + oom_stacks_hashmap->insertStackAndIncreaseCountIfExist(digest, &base_stack); + } + if(needCleanStackCache && oom_ptrs_hashmap->getRecordNum() > cache_clean_num){ + removeTinyMallocStacks(cache_clean_threshold); + cache_clean_num += oom_ptrs_hashmap->getRecordNum(); } } - unlockVMHashmap(); + do_unlockHashmap } } +void COOMDetector::removeTinyMallocStacks(size_t threshold) +{ + for(size_t i = 0; i < oom_ptrs_hashmap->getEntryNum(); i++){ + base_entry_t *entry = oom_ptrs_hashmap->getHashmapEntry() + i; + ptr_log_t *current = (ptr_log_t *)entry->root; + while(current != NULL){ + ptr_log_t *next = current->next; + merge_stack_t *lookupStack = oom_stacks_hashmap->lookupStack(current->digest); + if(lookupStack){ + uint32_t size = lookupStack->size; + uint64_t digest = lookupStack->digest; + uint32_t count = lookupStack->count; + vm_address_t address = current->address; + if(size < threshold){ + if(oom_ptrs_hashmap->removePtr(address,NULL,NULL)){ + oom_stacks_hashmap->removeIfCountIsZero(digest, size, count); + } + } + } + else { + vm_address_t address = current->address; + oom_ptrs_hashmap->removePtr(address,NULL,NULL); + } + current = next; + } + } +} -void COOMDetector::removeVMStack(vm_address_t address) +void COOMDetector::removeMallocStack(vm_address_t address) { - lockVMHashmap(); - if(vm_ptrs_hashmap && vm_stacks_hashmap){ - ptr_log_t *ptr_log = vm_ptrs_hashmap->lookupPtr(address); - if(ptr_log != NULL) - { - unsigned char md5[16]; - strncpy((char *)md5, (const char *)ptr_log->md5, 16); - size_t size = (size_t)ptr_log->size; - if(vm_ptrs_hashmap->removePtr(address)){ - vm_stacks_hashmap->removeIfCountIsZero(md5,size); + do_lockHashmap + if(oom_ptrs_hashmap && oom_stacks_hashmap){ + uint32_t size = 0; + uint64_t digest = 0; + uint32_t count = 1; + if(oom_ptrs_hashmap->removePtr(address,&size,&digest)){ + if(sampleFactor > 1 && size < sampleThreshold){ + count = sampleFactor; + size = size * sampleFactor; } + oom_stacks_hashmap->removeIfCountIsZero(digest, size, count); } } - unlockVMHashmap(); + do_unlockHashmap } -void COOMDetector::recordMallocStack(vm_address_t address,uint32_t size,const char*name,size_t stack_num_to_skip) +void COOMDetector::recordVMStack(vm_address_t address,uint32_t size,size_t stack_num_to_skip) { base_stack_t base_stack; base_ptr_log base_ptr; - unsigned char md5[16]; + uint64_t digest; vm_address_t *stack[max_stack_depth]; - if(needStackWithoutAppStack){ - base_stack.depth = stackHelper->recordBacktrace(needSysStack,0,stack_num_to_skip, stack,md5,max_stack_depth); - } - else { - base_stack.depth = stackHelper->recordBacktrace(needSysStack,1,stack_num_to_skip, stack,md5,max_stack_depth); - } - + base_stack.depth = (uint32_t)stackHelper->recordBacktrace(YES,1,0,stack_num_to_skip, stack,&digest,max_stack_depth); if(base_stack.depth > 0){ + base_stack.type = 1; + base_stack.size = size; + base_stack.count = 1; base_stack.stack = stack; - base_stack.extra.size = size; - base_ptr.md5 = md5; + base_ptr.digest = digest; base_ptr.size = size; - lockHashmap(); - if(oom_ptrs_hashmap && oom_stacks_hashmap){ - if(oom_ptrs_hashmap->insertPtr(address, &base_ptr)){ - oom_stacks_hashmap->insertStackAndIncreaseCountIfExist(md5, &base_stack); - } + do_lockVMHashmap + if(oom_vm_ptrs_hashmap && oom_vm_stacks_hashmap){ + oom_vm_ptrs_hashmap->insertPtr(address, &base_ptr); + oom_vm_stacks_hashmap->insertStackAndIncreaseCountIfExist(digest, &base_stack); } - unlockHashmap(); + do_unlockVMHashmap } } -void COOMDetector::removeMallocStack(vm_address_t address,monitor_mode mode) +void COOMDetector::removeVMStack(vm_address_t address) { - lockHashmap(); - if(oom_ptrs_hashmap && oom_stacks_hashmap){ - ptr_log_t *ptr_log = oom_ptrs_hashmap->lookupPtr(address); - if(ptr_log != NULL) - { - unsigned char md5[16]; - strncpy((char *)md5, (const char *)ptr_log->md5, 16); - size_t size = (size_t)ptr_log->size; - if(oom_ptrs_hashmap->removePtr(address)){ - oom_stacks_hashmap->removeIfCountIsZero(md5, size); - } + do_lockVMHashmap + if(oom_vm_ptrs_hashmap && oom_vm_stacks_hashmap){ + uint32_t size = 0; + uint64_t digest = 0; + if(oom_vm_ptrs_hashmap->removePtr(address,&size,&digest)){ + oom_vm_stacks_hashmap->removeIfCountIsZero(digest, size, 1); } } - unlockHashmap(); + do_unlockVMHashmap } -void COOMDetector::flush_allocation_stack() + + +void COOMDetector::initLogger(malloc_zone_t *zone, NSString *path, size_t mmap_size) { - normal_stack_logger->current_len = 0; - NSDateFormatter* df = [[NSDateFormatter new] autorelease]; - df.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS"; - NSString *dateStr = [df stringFromDate:[NSDate date]]; - int exceedNum = 0; - //flush malloc stack - if(enableOOMMonitor){ - lockHashmap(); - malloc_logger = NULL; - normal_stack_logger->sprintfLogger(grained_size,"%s normal_malloc_num:%ld stack_num:%ld\n",[dateStr UTF8String],oom_ptrs_hashmap->getRecordNum(),oom_stacks_hashmap->getRecordNum()); - for(size_t i = 0; i < oom_stacks_hashmap->getEntryNum(); i++){ - base_entry_t *entry = oom_stacks_hashmap->getHashmapEntry() + i; - merge_stack_t *current = (merge_stack_t *)entry->root; - while(current != NULL){ - if(current->extra.size > oom_threshold){ - exceedNum++; - normal_stack_logger->sprintfLogger(grained_size,"Malloc_size:%lfmb num:%u stack:\n",(double)(current->extra.size)/(1024*1024), current->count); - for(size_t j = 0; j < current ->depth; j++){ - vm_address_t addr = (vm_address_t)current->stack[j]; - segImageInfo segImage; - if(stackHelper->getImageByAddr(addr, &segImage)){ - normal_stack_logger->sprintfLogger(grained_size,"\"%lu %s 0x%lx 0x%lx\" ",j,(segImage.name != NULL) ? segImage.name : "unknown",segImage.loadAddr,(long)addr); - } - } - normal_stack_logger->sprintfLogger(grained_size,"\n"); - } - current = current->next; - } - } - malloc_logger = (malloc_logger_t *)common_stack_logger;//oom_malloc_logger; - unlockHashmap(); - } - normal_stack_logger->sprintfLogger(grained_size,"\n"); - //flush vm - if(enableVMMonitor){ - lockVMHashmap(); - *vm_sys_logger = NULL; - normal_stack_logger->sprintfLogger(grained_size,"%s vm_allocate_num:%ld stack_num:%ld\n",[dateStr UTF8String],vm_ptrs_hashmap->getRecordNum(),vm_stacks_hashmap->getRecordNum()); - for(size_t i = 0; i < vm_stacks_hashmap->getEntryNum(); i++){ - base_entry_t *entry = vm_stacks_hashmap->getHashmapEntry() + i; - merge_stack_t *current = (merge_stack_t *)entry->root; - while(current != NULL){ - if(current->extra.size > vm_threshold){ - exceedNum++; - normal_stack_logger->sprintfLogger(grained_size,"vm_allocate_size:%.2fmb num:%u type:%s stack:\n",(double)(current->extra.size)/(1024*1024), current->count,current->extra.name); - for(size_t j = 0; j < current ->depth; j++){ - vm_address_t addr = (vm_address_t)current->stack[j]; - segImageInfo segImage; - if(stackHelper->getImageByAddr(addr, &segImage)){ - normal_stack_logger->sprintfLogger(grained_size,"\"%lu %s 0x%lx 0x%lx\" ",j,(segImage.name != NULL) ? segImage.name : "unknown",segImage.loadAddr,(long)addr); - } - } - normal_stack_logger->sprintfLogger(grained_size,"\n"); - } - current = current->next; - } - } - } - if(exceedNum == 0){ - normal_stack_logger->cleanLogger(); - } - if(enableVMMonitor){ - *vm_sys_logger = oom_vm_logger; - } - unlockVMHashmap(); - normal_stack_logger->syncLogger(); + NSString *dir = [path stringByDeletingLastPathComponent]; + stackHelper = new CStackHelper(dir); + log_path = [path retain]; + log_mmap_size = mmap_size; } - -void COOMDetector::initLogger(malloc_zone_t *zone, NSString *path, size_t mmap_size,LogPrinter printer) +void COOMDetector::initVMLogger(malloc_zone_t *zone, NSString *path, size_t mmap_size) { - normal_stack_logger = new HighSpeedLogger(zone, path, mmap_size); - if(normal_stack_logger != NULL && normal_stack_logger->isValid()){ - normal_stack_logger->logPrinterCallBack = printer; + NSString *dir = [path stringByDeletingLastPathComponent]; + if(stackHelper == NULL){ + stackHelper = new CStackHelper(dir); } + vm_log_path = [path retain]; + vm_log_mmap_size = mmap_size; } BOOL COOMDetector::startMallocStackMonitor(size_t threshholdInBytes) { - if(normal_stack_logger != NULL && normal_stack_logger->isValid()){ - oom_stacks_hashmap = new CStacksHashmap(50000,global_memory_zone,OOMDetectorMode); - oom_stacks_hashmap->oom_threshold = threshholdInBytes; - oom_ptrs_hashmap = new CPtrsHashmap(250000,global_memory_zone); - enableOOMMonitor = YES; - oom_threshold = threshholdInBytes; - return YES; - } - else { - enableOOMMonitor = NO; - return NO; - } + oom_stacks_hashmap = new CStacksHashmap(50000,global_memory_zone,log_path,log_mmap_size); + oom_stacks_hashmap->oom_threshold = threshholdInBytes; + oom_ptrs_hashmap = new CPtrsHashmap(500000,global_memory_zone); + enableOOMMonitor = YES; + oom_threshold = threshholdInBytes; + return YES; } void COOMDetector::stopMallocStackMonitor() @@ -312,32 +320,29 @@ BOOL COOMDetector::startVMStackMonitor(size_t threshholdInBytes) { - if(normal_stack_logger != NULL && normal_stack_logger->isValid()){ - vm_stacks_hashmap = new CStacksHashmap(1000,global_memory_zone,OOMDetectorMode); - vm_ptrs_hashmap = new CPtrsHashmap(2000,global_memory_zone); - enableVMMonitor = YES; - vm_threshold = threshholdInBytes; - return YES; - } - else { - enableVMMonitor = NO; - return NO; - } + oom_vm_stacks_hashmap = new CStacksHashmap(1000,global_memory_zone,log_path,log_mmap_size); + oom_vm_stacks_hashmap->oom_threshold = threshholdInBytes; + oom_vm_ptrs_hashmap = new CPtrsHashmap(10000,global_memory_zone); + enableVMMonitor = YES; + vm_threshold = threshholdInBytes; +// rebind_symbols((struct rebinding[2]){ +// {"mmap",(void*)new_mmap,(void**)&orig_mmap}, +// {"munmap", (void*)new_munmap, (void **)&orig_munmap}}, +// 2); + return YES; } void COOMDetector::stopVMStackMonitor() { - if(normal_stack_logger != NULL){ - lockVMHashmap(); - CPtrsHashmap *tmp_ptr = vm_ptrs_hashmap; - CStacksHashmap *tmp_stack = vm_stacks_hashmap; - vm_ptrs_hashmap = NULL; - vm_stacks_hashmap = NULL; - unlockVMHashmap(); - delete tmp_ptr; - delete tmp_stack; - enableVMMonitor = NO; - } + enableVMMonitor = NO; + do_lockVMHashmap + CPtrsHashmap *tmp_ptr = oom_vm_ptrs_hashmap; + CStacksHashmap *tmp_stack = oom_vm_stacks_hashmap; + oom_vm_stacks_hashmap = NULL; + oom_vm_ptrs_hashmap = NULL; + do_unlockVMHashmap + delete tmp_ptr; + delete tmp_stack; } void COOMDetector::startSingleChunkMallocDetector(size_t threshholdInBytes,ChunkMallocBlock mallocBlock) @@ -347,7 +352,11 @@ if(chunkMallocCallback != NULL){ Block_release(chunkMallocCallback); } + if(chunk_stackHelper == NULL){ + chunk_stackHelper = new CStackHelper(nil); + } chunkMallocCallback = Block_copy(mallocBlock); + fileUploadCenter = [QQLeakFileUploadCenter defaultCenter]; } void COOMDetector::stopSingleChunkMallocDetector() @@ -355,8 +364,3 @@ enableChunkMonitor = NO; } -HighSpeedLogger *COOMDetector::getStackLogger() -{ - return normal_stack_logger; -} - diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/FOOMMonitor.h b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/FOOMMonitor.h new file mode 100644 index 0000000..88a00a7 --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/FOOMMonitor.h @@ -0,0 +1,98 @@ +// +// FOOMMonitor.h +// libOOMDetector +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + +#import + +@interface FOOMMonitor : NSObject + +/*! @brief 监控前台爆内存,原理参考:https://code.facebook.com/posts/1146930688654547/reducing-fooms-in-the-facebook-ios-app/ + * + */ ++(FOOMMonitor *)getInstance; + +/*! @brief 开始爆内存监控,不会影响性能,可以全网开启 + * + */ +-(void)start; + +/*! @brief 获取日志uuid,uuid每次启动会唯一生成 + * + */ +-(NSString *)getLogUUID; + +/*! @brief 获取当前记录的日志信息目录 + * + */ +-(NSString *)getLogPath; + +/*! @brief 为了保证数据准确,请在UIApplication delegate的applicationDidEnterBackground:回调第一时间调用该方法 + * + */ +-(void)appDidEnterBackground; + +/*! @brief 为了保证数据准确,请在UIApplication delegate的applicationWillEnterForeground:回调第一时间调用该方法 + * + */ +-(void)appWillEnterForground; + +/*! @brief 为了保证数据准确,请在UIApplication delegate的applicationWillTerminate:回调第一时间调用该方法 + * + */ +-(void)appWillTerminate; + +/*! @brief 请在Crash组件捕获到crash后调用该方法 + * + */ +-(void)appDidCrashed; + +/*! @brief 请在卡死检测组件检测到5秒以上卡顿时调用该方法 + * + */ +-(void)appDetectDeadLock:(NSDictionary *)stack; + +/*! @brief 请在卡死检测组件从5秒以上卡顿恢复时回调该方法 + * + */ +-(void)appResumeFromDeadLock; + +/*! @brief 如果开启了OOMDetector爆内存堆栈检测请设置该方法 + * + * @param isOpen YES表示开启了OOMDetector爆内存堆栈检测 + * + */ +-(void)setOOMDetectorOpen:(BOOL)isOpen; + + +/*! @brief 设置appVersion + * + * @param appVersion app版本号 + * + */ +-(void)setAppVersion:(NSString *)appVersion; + +/*! @brief SDK内部方法,不要直接调用 + * + */ +-(void)updateStage:(NSString *)stage; + +/*! @brief SDK内部方法,不要直接调用 + * + */ +-(void)appExit; + +@end diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/FOOMMonitor.mm b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/FOOMMonitor.mm new file mode 100644 index 0000000..56c4406 --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/FOOMMonitor.mm @@ -0,0 +1,533 @@ +// +// FOOMMonitor.mm +// libOOMDetector +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + + +#import "FOOMMonitor.h" +#import "HighSpeedLogger.h" +#import +#import "fishhook.h" +#import "QQLeakFileUploadCenter.h" +#import "OOMDetector.h" +#import "OOMDetectorLogger.h" +#import +#import "NSObject+FOOMSwizzle.h" + +#if !__has_feature(objc_arc) +#error This file must be compiled with ARC. Use -fobjc-arc flag. +#endif + +//#undef DEBUG +#define no_crash 0 +#define normal_crash 1 +#define deadlock_crash 2 +#define foom_crash 3 +#define foom_mmap_size 160*1024 + +static FOOMMonitor* monitor; + +static void (*_orig_exit)(int); +static void (*orig_exit)(int); + +void my_exit(int value) +{ + [[FOOMMonitor getInstance] appExit]; + orig_exit(value); +} + +void _my_exit(int value) +{ + [[FOOMMonitor getInstance] appExit]; + _orig_exit(value); +} + + +typedef enum{ + APPENTERBACKGROUND, + APPENTERFORGROUND, + APPDIDTERMINATE +}App_State; + +@interface UIViewController(FOOM) + +- (void)foom_viewDidAppear:(BOOL)animated; + +@end + +@implementation UIViewController(FOOM) + +- (void)foom_viewDidAppear:(BOOL)animated +{ + [self foom_viewDidAppear:animated]; + NSString *name = NSStringFromClass([self class]); + if( +#ifdef build_for_QQ + ![name hasPrefix:@"QUI"] && +#endif + ![name hasPrefix:@"_"] && ![name hasPrefix:@"UI"] && ![self isKindOfClass:[UINavigationController class]]) + { + [[FOOMMonitor getInstance] updateStage:name]; + } +} + +@end + +@interface FOOMMonitor() +{ + NSString *_uuid; + NSThread *_thread; + NSTimer *_timer; + NSUInteger _memWarningTimes; + NSUInteger _residentMemSize; + App_State _appState; + HighSpeedLogger *_foomLogger; + BOOL _isCrashed; + BOOL _isDeadLock; + BOOL _isExit; + NSDictionary *_deadLockStack; + NSString *_systemVersion; + NSString *_appVersion; + NSTimeInterval _ocurTime; + NSTimeInterval _startTime; + NSRecursiveLock *_logLock; + NSString *_currentLogPath; + BOOL _isDetectorStarted; + BOOL _isOOMDetectorOpen; + NSString *_crash_stage; +} + +@end + +@implementation FOOMMonitor + ++(FOOMMonitor *)getInstance +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + monitor = [FOOMMonitor new]; + }); + return monitor; +} + +-(id)init{ + if(self = [super init]){ + _uuid = [self uuid]; + _logLock = [NSRecursiveLock new]; + _thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain) object:nil]; + [_thread setName:@"foomMonitor"]; + _timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(updateMemory) userInfo:nil repeats:YES]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; + [_thread start]; + } + return self; +} + +-(void)createmmapLogger +{ + [_logLock lock]; + [self hookExitAndAbort]; + [self swizzleMethods]; + NSString *dir = [self foomMemoryDir]; + _systemVersion = [[NSProcessInfo processInfo] operatingSystemVersionString]; + _currentLogPath = [dir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.oom",_uuid]]; + _foomLogger = new HighSpeedLogger(malloc_default_zone(), _currentLogPath, foom_mmap_size); + _crash_stage = @" "; + int32_t length = 0; + if(_foomLogger && _foomLogger->isValid()){ + _foomLogger->memcpyLogger((const char *)&length, 4); + } + [self updateFoomData]; + [self uploadLastData]; + [_logLock unlock]; +} + +-(NSString *)uuid +{ + CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); + CFStringRef strUuid = CFUUIDCreateString(kCFAllocatorDefault,uuid); + NSString * str = [NSString stringWithString:(__bridge NSString *)strUuid]; + CFRelease(strUuid); + CFRelease(uuid); + return str; +} + +-(NSString *)getLogUUID +{ + return _uuid; +} + +-(NSString *)getLogPath { + return _currentLogPath; +} + +-(void)start +{ + _isDetectorStarted = YES; + if([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) + { + _appState = APPENTERBACKGROUND; + } + else { + _appState = APPENTERFORGROUND; + } + _isCrashed = NO; + _isExit = NO; + _isDeadLock = NO; + _ocurTime = [[NSDate date] timeIntervalSince1970]; + _startTime = _ocurTime; + [self performSelector:@selector(createmmapLogger) onThread:_thread withObject:nil waitUntilDone:NO]; +} + +-(void)hookExitAndAbort +{ + rebind_symbols((struct rebinding[2]){{"_exit", (void *)_my_exit, (void **)&_orig_exit}, {"exit", (void *)my_exit, (void **)&orig_exit}}, 2); +} + +-(void)swizzleMethods +{ + [UIViewController swizzleMethod:@selector(viewDidAppear:) withMethod:@selector(foom_viewDidAppear:)]; +} + + +-(void)threadMain +{ + [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; + [[NSRunLoop currentRunLoop] run]; + [_timer fire]; +} + +-(void)updateMemory +{ + [_logLock lock]; + if(_appState == APPENTERFORGROUND){ + NSUInteger memSize = (NSUInteger)[self appResidentMemory]; + if(_isDeadLock){ + if(abs((int)(_residentMemSize - memSize)) < 5){ + //卡死状态下内存无明显变化就不update了,避免CPU过高发热 + [_logLock unlock]; + return ; + } + } + _residentMemSize = memSize; + } + _ocurTime = [[NSDate date] timeIntervalSince1970]; + [self updateFoomData]; + [_logLock unlock]; +} + +-(void)updateFoomData{ + if(_foomLogger && _foomLogger->isValid()){ + NSString* residentMemory = [NSString stringWithFormat:@"%lu", (unsigned long)_residentMemSize]; + NSDictionary *foomDict = [NSDictionary dictionaryWithObjectsAndKeys:residentMemory,@"lastMemory",[NSNumber numberWithUnsignedLongLong:_memWarningTimes],@"memWarning",_uuid,@"uuid",_systemVersion,@"systemVersion",_appVersion,@"appVersion",[NSNumber numberWithInt:(int)_appState],@"appState",[NSNumber numberWithBool:_isCrashed],@"isCrashed",[NSNumber numberWithBool:_isDeadLock],@"isDeadLock",_deadLockStack ? _deadLockStack : @"",@"deadlockStack",[NSNumber numberWithBool:_isExit],@"isExit",[NSNumber numberWithDouble:_ocurTime],@"ocurTime",[NSNumber numberWithDouble:_startTime],@"startTime",[NSNumber numberWithBool:_isOOMDetectorOpen],@"isOOMDetectorOpen",_crash_stage,@"crash_stage",nil]; + NSData *foomData = [NSKeyedArchiver archivedDataWithRootObject:foomDict]; + if(foomData && [foomData length] > 0){ + _foomLogger->cleanLogger(); + int32_t length = (int32_t)[foomData length]; + if(!_foomLogger->memcpyLogger((const char *)&length, 4)){ + [[NSFileManager defaultManager] removeItemAtPath:_currentLogPath error:nil]; + delete _foomLogger; + _foomLogger = NULL; + } + else { + if(!_foomLogger->memcpyLogger((const char *)[foomData bytes],[foomData length])){ + [[NSFileManager defaultManager] removeItemAtPath:_currentLogPath error:nil]; + delete _foomLogger; + _foomLogger = NULL; + } + } + } + } +} + +-(void)uploadLastData +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSString *foomDir = [self foomMemoryDir]; + NSFileManager *fm = [NSFileManager defaultManager]; + NSArray *paths = [fm contentsOfDirectoryAtPath:foomDir error:nil]; + for(NSString *path in paths) + { + if([path hasSuffix:@".oom"]){ + NSString *fullPath = [foomDir stringByAppendingPathComponent:path]; + if([fullPath isEqualToString:_currentLogPath]){ + continue; + } + NSData *metaData = [NSData dataWithContentsOfFile:fullPath]; + if(metaData.length <= 4){ + [fm removeItemAtPath:fullPath error:nil]; + continue; + } + int32_t length = *(int32_t *)metaData.bytes; + if(length <= 0 || length > [metaData length] - 4){ + [fm removeItemAtPath:fullPath error:nil]; + } + else { + NSData *foomData = [NSData dataWithBytes:(const char *)metaData.bytes + 4 length:(NSUInteger)length]; + NSDictionary *foomDict = nil; + @try { + foomDict = [NSKeyedUnarchiver unarchiveObjectWithData:foomData]; + } + @catch (NSException *e) { + foomDict = nil; + OOM_Log("unarchive FOOMData failed,length:%d,exception:%s!",length,[[e description] UTF8String]); + } + @finally{ + if(foomDict && [foomDict isKindOfClass:[NSDictionary class]]){ + NSString *uin = [foomDict objectForKey:@"uin"]; + if(uin == nil || uin.length <= 0){ + uin = @"10000"; + } + NSDictionary *uploadData = [self parseFoomData:foomDict]; + NSDictionary *aggregatedData = [NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObject:uploadData],@"parts",nil]; + NSString *uuid = [foomDict objectForKey:@"uuid"]; + NSDictionary *basicParameter = [NSDictionary dictionaryWithObjectsAndKeys:uin,@"uin",uuid,@"client_identify",[foomDict objectForKey:@"ocurTime"],@"occur_time",nil]; + [[QQLeakFileUploadCenter defaultCenter] fileData:aggregatedData extra:basicParameter type:QQStackReportTypeOOMLog completionHandler:nil]; + } + [fm removeItemAtPath:fullPath error:nil]; + } + } + } + } + [[OOMDetector getInstance] clearOOMLog]; + }); +} + +-(NSDictionary *)parseFoomData:(NSDictionary *)foomDict +{ + NSMutableDictionary *result = [NSMutableDictionary new]; + [result setObject:@"sigkill" forKey:@"category"]; + NSNumber *startTime = [foomDict objectForKey:@"startTime"]; + if(startTime){ + [result setObject:startTime forKey:@"s"]; + } + [result setObject:[foomDict objectForKey:@"ocurTime"] forKey:@"e"]; + [result setObject:[foomDict objectForKey:@"lastMemory"] forKey:@"mem_used"]; + [result setObject:[foomDict objectForKey:@"memWarning"] forKey:@"mem_warning_cnt"]; + NSString *crash_stage = [foomDict objectForKey:@"crash_stage"]; + if(crash_stage){ + [result setObject:crash_stage forKey:@"crash_stage"]; + } + NSNumber *isOOMDetectorOpen_num = [foomDict objectForKey:@"isOOMDetectorOpen"]; + if(isOOMDetectorOpen_num){ + [result setObject:isOOMDetectorOpen_num forKey:@"enable_oom"]; + } + else { + [result setObject:@NO forKey:@"enable_oom"]; + } + App_State appState = (App_State)[[foomDict objectForKey:@"appState"] intValue]; + BOOL isCrashed = [[foomDict objectForKey:@"isCrashed"] boolValue]; + if(appState == APPENTERFORGROUND){ + BOOL isExit = [[foomDict objectForKey:@"isExit"] boolValue]; + BOOL isDeadLock = [[foomDict objectForKey:@"isDeadLock"] boolValue]; + NSString *lastSysVersion = [foomDict objectForKey:@"systemVersion"]; + NSString *lastAppVersion = [foomDict objectForKey:@"appVersion"]; + if(!isCrashed && !isExit && [_systemVersion isEqualToString:lastSysVersion] && [_appVersion isEqualToString:lastAppVersion]){ + if(isDeadLock){ + OOM_Log("The app ocurred deadlock lastTime,detail info:%s",[[foomDict description] UTF8String]); + [result setObject:@deadlock_crash forKey:@"crash_type"]; + NSDictionary *stack = [foomDict objectForKey:@"deadlockStack"]; + if(stack && stack.count > 0){ + [result setObject:stack forKey:@"stack_deadlock"]; + OOM_Log("The app deadlock stack:%s",[[stack description] UTF8String]); + } + } + else { + OOM_Log("The app ocurred foom lastTime,detail info:%s",[[foomDict description] UTF8String]); + [result setObject:@foom_crash forKey:@"crash_type"]; + NSString *uuid = [foomDict objectForKey:@"uuid"]; + NSArray *oomStack = [[OOMDetector getInstance] getOOMDataByUUID:uuid]; + if(oomStack && oomStack.count > 0) + { + NSData *oomData = [NSJSONSerialization dataWithJSONObject:oomStack options:0 error:nil]; + if(oomData.length > 0){ +// NSString *stackStr = [NSString stringWithUTF8String:(const char *)oomData.bytes]; + OOM_Log("The app foom stack:%s",[[oomStack description] UTF8String]); + } + [result setObject:[self getAPMOOMStack:oomStack] forKey:@"stack_oom"]; + } + } + return result; + } + } + if(isCrashed){ + OOM_Log("The app ocurred rqd crash lastTime,detail info:%s",[[foomDict description] UTF8String]); + [result setObject:@normal_crash forKey:@"crash_type"]; + } + else { + OOM_Log("The app ocurred no crash lastTime,detail info:%s!",[[foomDict description] UTF8String]); + [result setObject:@no_crash forKey:@"crash_type"]; + } + [result setObject:@"" forKey:@"stack_deadlock"]; + [result setObject:@"" forKey:@"stack_oom"]; + return result; +} + +-(NSDictionary *)getAPMOOMStack:(NSArray *)stack +{ + NSDictionary *slice = [NSDictionary dictionaryWithObjectsAndKeys:stack,@"threads",nil]; + NSArray *slicesArray = [NSArray arrayWithObject:slice]; + NSDictionary *result = [NSDictionary dictionaryWithObjectsAndKeys:slicesArray,@"time_slices",nil]; + return result; +} + +-(NSString*)foomMemoryDir +{ + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); + NSString *LibDirectory = [paths objectAtIndex:0]; + NSString *path = [LibDirectory stringByAppendingPathComponent:@"/Foom"]; + if(![[NSFileManager defaultManager] fileExistsAtPath:path]){ + [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; + } + return path; +} + +- (double)appResidentMemory +{ + mach_task_basic_info_data_t taskInfo; + unsigned infoCount = sizeof(taskInfo); + kern_return_t kernReturn = task_info(mach_task_self(), + MACH_TASK_BASIC_INFO, + (task_info_t)&taskInfo, + &infoCount); + + if (kernReturn != KERN_SUCCESS + ) { + return 0; + } + return taskInfo.resident_size / 1024.0 / 1024.0; +} + +-(void)setOOMDetectorOpen:(BOOL)isOpen +{ + [_logLock lock]; + _isOOMDetectorOpen = isOpen; + [self updateFoomData]; + [_logLock unlock]; +} + +-(void)updateStage:(NSString *)stage +{ + [self performSelector:@selector(_updateStage:) onThread:_thread withObject:stage waitUntilDone:NO]; +} + +-(void)_updateStage:(NSString *)stage +{ + [_logLock lock]; + _crash_stage = stage; + [self updateFoomData]; + [_logLock unlock]; +} + +-(void)appReceiveMemoryWarning +{ + [self performSelector:@selector(_appReceiveMemoryWarning) onThread:_thread withObject:nil waitUntilDone:NO]; +} + +-(void)_appReceiveMemoryWarning +{ + [_logLock lock]; + _memWarningTimes++; + [self updateFoomData]; + [_logLock unlock]; +} + +-(void)appDidEnterBackground +{ + [self performSelector:@selector(_appDidEnterBackground) onThread:_thread withObject:nil waitUntilDone:NO]; +} + +-(void)_appDidEnterBackground +{ + [_logLock lock]; + _appState = APPENTERBACKGROUND; + [self updateFoomData]; + [_logLock unlock]; +} + +-(void)appWillEnterForground +{ + [self performSelector:@selector(_appWillEnterForground) onThread:_thread withObject:nil waitUntilDone:NO]; +} + +-(void)_appWillEnterForground +{ + [_logLock lock]; + if(_appState != APPDIDTERMINATE) + { + _appState = APPENTERFORGROUND; + [self updateFoomData]; + } + [_logLock unlock]; +} + +-(void)appWillTerminate +{ + [self _appWillTerminate]; +} + +-(void)_appWillTerminate +{ + [_logLock lock]; + _appState = APPDIDTERMINATE; + [self updateFoomData]; + [_logLock unlock]; +} + +-(void)appDidCrashed +{ + [_logLock lock]; + _isCrashed = YES; + [self updateFoomData]; + [_logLock unlock]; +} + + +-(void)appExit +{ + [_logLock lock]; + _isExit = YES; + [self updateFoomData]; + [_logLock unlock]; +} + +-(void)appDetectDeadLock:(NSDictionary *)stack +{ + [_logLock lock]; + _isDeadLock = YES; + _deadLockStack = stack; +// _deadLockStack = stack; + [self updateFoomData]; + [_logLock unlock]; +} + +-(void)appResumeFromDeadLock +{ + [_logLock lock]; + _isDeadLock = NO; + _deadLockStack = nil; + [self updateFoomData]; + [_logLock unlock]; +} + +-(void)setAppVersion:(NSString *)appVersion +{ + [_logLock lock]; + _appVersion = appVersion; + [_logLock unlock]; +} + +@end diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/HighSpeedLogger.h b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/HighSpeedLogger.h new file mode 100644 index 0000000..02973e7 --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/HighSpeedLogger.h @@ -0,0 +1,46 @@ +// +// HighSpeedLogger.h +// QQLeak +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + +#ifndef HighSpeedLogger_h +#define HighSpeedLogger_h + +#import +#import + +typedef void (*LogPrinter)(char *log); + +class HighSpeedLogger +{ +public: + ~HighSpeedLogger(); + HighSpeedLogger(malloc_zone_t *zone, NSString *path, size_t mmap_size); + BOOL memcpyLogger(const char *content, size_t length); + void cleanLogger(); + void syncLogger(); + bool isValid(); + LogPrinter logPrinterCallBack; +public: + char *mmap_ptr; + size_t mmap_size; + size_t current_len; + malloc_zone_t *memory_zone; + FILE *mmap_fp; + bool isFailed; +}; + +#endif /* HighSpeedLogger_h */ diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/HighSpeedLogger.mm b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/HighSpeedLogger.mm new file mode 100644 index 0000000..5cc918f --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/HighSpeedLogger.mm @@ -0,0 +1,118 @@ +// +// HighSpeedLogger.m +// QQLeak +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + +#import "HighSpeedLogger.h" +#import + +#if __has_feature(objc_arc) +#error This file must be compiled without ARC. Use -fno-objc-arc flag. +#endif + +HighSpeedLogger::~HighSpeedLogger() +{ + if(mmap_ptr != NULL){ + munmap(mmap_ptr , mmap_size); + } +} + +HighSpeedLogger::HighSpeedLogger(malloc_zone_t *zone, NSString *path, size_t size) +{ + current_len = 0; + mmap_size = size; + memory_zone = zone; + isFailed = false; + FILE *fp = fopen ( [path fileSystemRepresentation] , "wb+" ) ; + if(fp != NULL){ + int ret = ftruncate(fileno(fp), size); + if(ret == -1){ + isFailed = true; + } + else { + fseek(fp, 0, SEEK_SET); + char *ptr = (char *)mmap(0, size, PROT_WRITE | PROT_READ, (MAP_FILE|MAP_SHARED), fileno(fp), 0); + memset(ptr, '\0', size); + if(ptr != NULL){ + mmap_ptr = ptr; + mmap_fp = fp; + } + else { + isFailed = true; + } + } + } + else { + isFailed = true; + } +} + +BOOL HighSpeedLogger::memcpyLogger(const char *content, size_t length) +{ + BOOL result = NO; + if(length + current_len <= mmap_size){ + memcpy(mmap_ptr + current_len, content, length); + current_len += length; + result = YES; + } + else { + char *copy = (char *)memory_zone->malloc(memory_zone, mmap_size); + memcpy(copy, mmap_ptr, mmap_size); + size_t copy_size = mmap_size; + munmap(mmap_ptr ,mmap_size); + mmap_size = current_len + length; + int ret = ftruncate(fileno(mmap_fp), mmap_size); + if(ret == -1){ + memory_zone->free(memory_zone,copy); + result = NO; + } + else { + fseek(mmap_fp, 0, SEEK_SET); + mmap_ptr = (char *)mmap(0, mmap_size, PROT_WRITE | PROT_READ, (MAP_FILE|MAP_SHARED), fileno(mmap_fp), 0); + if(mmap_ptr == NULL){ + mmap_size = 0; + current_len = 0; + memory_zone->free(memory_zone,copy); + result = NO; + } + else { + memset(mmap_ptr, '\0', mmap_size); + result = YES; + memcpy(mmap_ptr, copy, copy_size); + memcpy(mmap_ptr + current_len, content, length); + current_len += length; + memory_zone->free(memory_zone,copy); + } + } + } + return result; +} + +void HighSpeedLogger::cleanLogger() +{ + current_len = 0; + memset(mmap_ptr, '\0', mmap_size); +} + +void HighSpeedLogger::syncLogger() +{ + msync(mmap_ptr, mmap_size, MS_ASYNC); +} + +bool HighSpeedLogger::isValid() +{ + return !isFailed; +} diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/OOMDetector.mm b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/OOMDetector.mm index e5eb8d5..27cfc89 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/OOMDetector.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/main/OOMDetector.mm @@ -1,6 +1,6 @@ // // OOMDetector.mm -// QQLeak +// libOOMDetector // // Tencent is pleased to support the open source community by making OOMDetector available. // Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. @@ -24,7 +24,6 @@ #import "stdio.h" #import "OOMMemoryStackTracker.h" #import "QQLeakPredefines.h" -#import "HighSpeedLogger.h" #import "CStackHelper.h" #import "OOMDetector.h" #import "CStacksHashmap.h" @@ -33,30 +32,24 @@ #import "QQLeakFileUploadCenter.h" #import "QQLeakDeviceInfo.h" #import "CommonMallocLogger.h" +#import "RapidCRC.h" +#import "CStackHighSpeedLogger.h" +#import "CStackHelper.h" +#import "COOMDetector.h" #if __has_feature(objc_arc) #error This file must be compiled without ARC. Use -fno-objc-arc flag. #endif -#if defined(USE_VM_LOGGER_FORCEDLY) || defined(DEBUG) -#define USE_VM_LOGGER -#endif - -#ifdef USE_VM_LOGGER - -#if defined(USE_VM_LOGGER_FORCEDLY) -#warning 请务必在提交app store审核之前注释掉“USE_VM_LOGGER_FORCEDLY”宏!!! -#endif - -//__syscall_logger是系统私有API,在appstore版本千万不要引用!!!!! -extern malloc_logger_t* __syscall_logger; - +#ifdef build_for_QQ +malloc_zone_t *nano_gurd_zone; #endif +extern malloc_zone_t *global_memory_zone; +extern logCallback oom_logger; //static static OOMDetector *catcher; static size_t normal_size = 512*1024; -//malloc_logger_t** vm_sys_logger; COOMDetector* global_oomdetector; void printLog(char *log) @@ -76,12 +69,9 @@ void myChunkMallocCallback(size_t bytes, NSString *stack) @interface OOMDetector() { NSString *_normal_path; - NSRecursiveLock *_flushLock; - NSTimer *_timer; - double _dumpLimit; - BOOL _needAutoDump; QQLeakChecker *_leakChecker; NSString *_currentDir; + NSString *_normal_vm_path; BOOL _enableOOMMonitor; BOOL _enableChunkMonitor; BOOL _enableVMMonitor; @@ -96,7 +86,6 @@ +(OOMDetector *)getInstance static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ catcher = [OOMDetector new]; - global_oomdetector = new COOMDetector(); }); return catcher; } @@ -104,23 +93,20 @@ +(OOMDetector *)getInstance -(id)init { if(self = [super init]){ - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); - NSString *LibDirectory = [paths objectAtIndex:0]; - NSDateFormatter* df = [[NSDateFormatter new] autorelease]; - df.dateFormat = @"yyyyMMdd_HHmmssSSS"; - NSString *dateStr = [df stringFromDate:[NSDate date]]; - _currentDir = [[LibDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"OOMDetector/%@",dateStr]] retain]; - _normal_path = [[_currentDir stringByAppendingPathComponent:[NSString stringWithFormat:@"normal_malloc%@.log",dateStr]] retain]; + global_oomdetector = new COOMDetector(); if(global_memory_zone == nil){ global_memory_zone = malloc_create_zone(0, 0); malloc_set_zone_name(global_memory_zone, "OOMDetector"); } - _flushLock = [NSRecursiveLock new]; - } return self; } +-(void)registerLogCallback:(logCallback)logger +{ + oom_logger = logger; +} + - (void)setupWithDefaultConfig { CGFloat OOMThreshhold = 300.f; @@ -160,8 +146,8 @@ - (void)setupLeakChecker QQLeakChecker *leakChecker = [QQLeakChecker getInstance]; _leakChecker = leakChecker; - //设置堆栈最大长度为10,超过10将被截断 - [leakChecker setMaxStackDepth:10]; + //设置堆栈最大长度为25,超过25将被截断 + [leakChecker setMaxStackDepth:25]; [leakChecker setNeedSystemStack:YES]; //开始记录对象分配堆栈 [leakChecker startStackLogging]; @@ -177,11 +163,6 @@ - (void)executeLeakCheck:(QQLeakCheckCallback)callback [[self currentLeakChecker] executeLeakCheck:callback]; } --(void)registerLogCallback:(logCallback)logger -{ - oom_logger = logger; -} - -(void)startMaxMemoryStatistic:(double)overFlowLimit { @@ -189,88 +170,82 @@ -(void)startMaxMemoryStatistic:(double)overFlowLimit } --(BOOL)startMallocStackMonitor:(size_t)threshholdInBytes needAutoDumpWhenOverflow:(BOOL)needAutoDump dumpLimit:(double)dumpLimit sampleInterval:(NSTimeInterval)sampleInterval + +-(BOOL)startMallocStackMonitor:(size_t)threshholdInBytes logUUID:(NSString *)uuid { if(!_enableOOMMonitor){ - - if(global_oomdetector->getStackLogger() == NULL){ - NSFileManager *fileManager = [NSFileManager defaultManager]; - if (![fileManager fileExistsAtPath:_currentDir]) { - [fileManager createDirectoryAtPath:_currentDir withIntermediateDirectories:YES attributes:nil error:nil]; - } - if (![fileManager fileExistsAtPath:_normal_path]) { - [fileManager createFileAtPath:_normal_path contents:nil attributes:nil]; - } - global_oomdetector->initLogger(global_memory_zone, _normal_path, normal_size,printLog); + _currentDir = [[[self OOMDataPath] stringByAppendingPathComponent:uuid] retain]; + _normal_path = [[_currentDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mmap",uuid]] retain]; + init_crc_table_for_oom(); + NSFileManager *fileManager = [NSFileManager defaultManager]; + if (![fileManager fileExistsAtPath:_currentDir]) { + [fileManager createDirectoryAtPath:_currentDir withIntermediateDirectories:YES attributes:nil error:nil]; + } + if (![fileManager fileExistsAtPath:_normal_path]) { + [fileManager createFileAtPath:_normal_path contents:nil attributes:nil]; } + global_oomdetector->initLogger(global_memory_zone, _normal_path, normal_size); _enableOOMMonitor = global_oomdetector->startMallocStackMonitor(threshholdInBytes); if(_enableOOMMonitor){ - malloc_logger = (malloc_logger_t *)common_stack_logger;//(malloc_logger_t *)oom_malloc_logger; + malloc_logger = (malloc_logger_t *)common_stack_logger; } } - if(needAutoDump){ - _dumpLimit = dumpLimit; - _timer = [NSTimer timerWithTimeInterval:sampleInterval target:self selector:@selector(detectorTask) userInfo:nil repeats:YES]; - [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; - [_timer fire]; - } - return _enableOOMMonitor; } --(void)detectorTask +-(void)stopMallocStackMonitor { - double currentMemory = [QQLeakDeviceInfo appUsedMemory]; - //flush stack - if(currentMemory > _dumpLimit){ - [self flush_allocation_stack]; + if(_enableOOMMonitor){ + malloc_logger = NULL; + global_oomdetector->stopMallocStackMonitor(); } + } +-(void)setMallocSampleFactor:(uint32_t)factor +{ + global_oomdetector->sampleFactor = factor; +} --(void)stopMallocStackMonitor +-(void)setMallocNoSampleThreshold:(uint32_t)threshhold +{ + global_oomdetector->sampleThreshold = threshhold; +} + +-(void)setNeedCleanStack:(BOOL)isNeed maxStackNum:(size_t)maxNum minimumStackSize:(size_t)mininumSize { if(_enableOOMMonitor){ - global_oomdetector->stopMallocStackMonitor(); + global_oomdetector->needCleanStackCache = isNeed; + global_oomdetector->cache_clean_num = maxNum; + global_oomdetector->cache_clean_threshold = mininumSize; } - if(_timer){ - [_timer invalidate]; - } - } --(void)setupVMLogger +-(void)setVMLogger:(void**)logger { -#ifdef USE_VM_LOGGER - global_oomdetector->vm_sys_logger = (malloc_logger_t**)&__syscall_logger; -#else - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"你在Release模式下调用了startVMStackMonitor:方法,Release模式下只有打开了USE_VM_LOGGER_FORCEDLY宏之后startVMStackMonitor:方法才会生效,不过切记不要在app store版本中打开USE_VM_LOGGER_FORCEDLY宏" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; - [alert show]; -#endif - + global_oomdetector->vm_sys_logger = (malloc_logger_t**)logger; } --(BOOL)startVMStackMonitor:(size_t)threshHoldInbytes +-(BOOL)startVMStackMonitor:(size_t)threshHoldInbytes logUUID:(NSString *)uuid { - if (NULL == global_oomdetector->vm_sys_logger) { - [self setupVMLogger]; - } - if(!_enableVMMonitor && global_oomdetector->vm_sys_logger){ - if(global_oomdetector->getStackLogger() == NULL){ - NSFileManager *fileManager = [NSFileManager defaultManager]; - if (![fileManager fileExistsAtPath:_currentDir]) { - [fileManager createDirectoryAtPath:_currentDir withIntermediateDirectories:YES attributes:nil error:nil]; - } - if (![fileManager fileExistsAtPath:_normal_path]) { - [fileManager createFileAtPath:_normal_path contents:nil attributes:nil]; - } - global_oomdetector->initLogger(global_memory_zone, _normal_path, normal_size,printLog); + if(!_enableVMMonitor){ + _normal_vm_path = [[_currentDir stringByAppendingPathComponent:[NSString stringWithFormat:@"vm_%@.mmap",uuid]] retain]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if (![fileManager fileExistsAtPath:_currentDir]) { + [fileManager createDirectoryAtPath:_currentDir withIntermediateDirectories:YES attributes:nil error:nil]; + } + if (![fileManager fileExistsAtPath:_normal_vm_path]) { + [fileManager createFileAtPath:_normal_vm_path contents:nil attributes:nil]; } + global_oomdetector->initLogger(global_memory_zone, _normal_vm_path, normal_size); _enableVMMonitor = global_oomdetector->startVMStackMonitor(threshHoldInbytes); if(_enableVMMonitor){ - *(global_oomdetector->vm_sys_logger) = oom_vm_logger; + if(global_oomdetector->vm_sys_logger != NULL) + { + *(global_oomdetector->vm_sys_logger) = oom_vm_logger; + } } } return YES; @@ -278,9 +253,12 @@ -(BOOL)startVMStackMonitor:(size_t)threshHoldInbytes -(void)stopVMStackMonitor { - if(_enableVMMonitor && global_oomdetector->vm_sys_logger){ + if(_enableVMMonitor){ + if(global_oomdetector->vm_sys_logger != NULL) + { + *(global_oomdetector->vm_sys_logger) = NULL; + } global_oomdetector->stopVMStackMonitor(); - *(global_oomdetector->vm_sys_logger) = NULL; _enableVMMonitor = NO; } } @@ -292,7 +270,7 @@ -(BOOL)startSingleChunkMallocDetector:(size_t)threshholdInBytes callback:(ChunkM if(_enableChunkMonitor){ global_oomdetector->startSingleChunkMallocDetector(threshholdInBytes,callback); self.chunkMallocBlock = callback; - malloc_logger = (malloc_logger_t *)common_stack_logger;//(malloc_logger_t *)oom_malloc_logger; + malloc_logger = (malloc_logger_t *)common_stack_logger; } } return _enableChunkMonitor; @@ -307,62 +285,120 @@ -(void)stopSingleChunkMallocDetector _enableChunkMonitor = NO; } --(void)flush_allocation_stack +-(NSArray *)getOOMDataByUUID:(NSString *)uuid { - [_flushLock lock]; - global_oomdetector->flush_allocation_stack(); - [_flushLock unlock]; + NSArray *images = [self getOOMImageDataByUUID:uuid]; + NSMutableArray *stacks = [[[NSMutableArray alloc] init] autorelease]; + if(images){ + NSData *mallocData = [self getOOMMallocDataByUUID:uuid]; + NSData *vmData = [self getOOMVMDataByUUID:uuid]; + if(mallocData.length > 0){ + NSArray *mallocStack = [self parseOOMData:mallocData images:images isVM:NO]; + [stacks addObjectsFromArray:mallocStack]; + } + if(vmData.length > 0){ + NSArray *vmStack = [self parseOOMData:vmData images:images isVM:YES]; + [stacks addObjectsFromArray:vmStack]; + } + } + [self removeOOMDataByUUID:uuid]; + return stacks; } --(void)uploadAllStack +-(NSArray *)parseOOMData:(NSData *)oomData images:(NSArray *)images isVM:(BOOL)isVM { - if ([QQLeakFileUploadCenter defaultCenter].fileDataDelegate) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSFileManager *fm = [NSFileManager defaultManager]; - NSString *OOMDataPath = [self OOMDataPath]; - NSString *currentLogDir = [self currentStackLogDir]; - NSArray *paths = [fm contentsOfDirectoryAtPath:OOMDataPath error:nil]; - for(NSString *path in paths) - { - NSString *fullPath = [OOMDataPath stringByAppendingPathComponent:path]; - BOOL isDir = NO; - if([fm fileExistsAtPath:fullPath isDirectory:&isDir]){ - if(!isDir) continue; - - if(currentLogDir == nil || (currentLogDir != nil && ![fullPath isEqualToString:currentLogDir])){ - - NSDirectoryEnumerator *internal_enumerator = [fm enumeratorAtPath:fullPath]; - NSString *internal_path = [internal_enumerator nextObject]; - - while(internal_path != nil){ - QQStackReportType reportType = QQStackReportTypeOOMLog; - NSString *internal_full_path = [fullPath stringByAppendingPathComponent:internal_path]; - NSData *data = [NSData dataWithContentsOfFile:internal_full_path]; - size_t stack_size = strlen((char *)data.bytes); - - if(stack_size == 0){ - [fm removeItemAtPath:fullPath error:nil]; - } - - if(![internal_path hasPrefix:@"normal_malloc"]){ - reportType = QQStackReportTypeChunkMemory; - } - - if (stack_size > 0 && data.length > 0) { - NSDictionary *extra = [NSDictionary dictionaryWithObjectsAndKeys:[[UIDevice currentDevice] systemVersion],@"systemversion",[QQLeakDeviceInfo platform],@"Device",@"normal_malloc",@"type",nil]; - [[QQLeakFileUploadCenter defaultCenter] fileData:data extra:extra type:reportType completionHandler:^(BOOL completed) { - if (completed) { - [fm removeItemAtPath:fullPath error:nil]; - } - }]; - } - - internal_path = [internal_enumerator nextObject]; - } + AppImages *app_images = CStackHelper::parseImages(images); + cache_stack_t *mmap_ptr = (cache_stack_t *)oomData.bytes; + size_t stack_num = oomData.length/sizeof(cache_stack_t); + NSMutableArray *stacks = [[[NSMutableArray alloc] init] autorelease]; + if(oomData && oomData.length > 0 && app_images->size > 0) + { + for(size_t offset = 0; offset < stack_num;offset++) + { + cache_stack_t *cache_stack = mmap_ptr + offset; + if(cache_stack->count > 0){ + NSMutableDictionary *stack = [[NSMutableDictionary new] autorelease]; + if(!isVM){ + [stack setObject:@"malloc" forKey:@"stack_type"]; + } + else { + [stack setObject:@"vm" forKey:@"stack_type"]; + } + [stack setObject:[NSNumber numberWithInteger:(NSInteger)cache_stack->size] forKey:@"malloc_size"]; + [stack setObject:[NSNumber numberWithInteger:(NSInteger)cache_stack->count] forKey:@"malloc_count"]; + NSMutableArray *calls = [[NSMutableArray new] autorelease]; + for(size_t j = 0; j < cache_stack->stack_depth; j++){ + vm_address_t addr = (vm_address_t)cache_stack->stacks[j]; + segImageInfo segImage; + if(CStackHelper::parseAddrOfImages(app_images,addr, &segImage)){ + [calls addObject:[NSString stringWithFormat:@"%lu %s 0x%lx 0x%lx",j,(segImage.name != NULL) ? segImage.name : "unknown",segImage.loadAddr,(long)addr]]; } } + NSDictionary *frame = [NSDictionary dictionaryWithObjectsAndKeys:calls,@"calls",nil]; + [stack setObject:frame forKey:@"frame"]; + [stacks addObject:stack]; } - }); + } + } + for (size_t i = 0; i < app_images->size; i++) + { + free(app_images->imageInfos[i]); + } + free(app_images->imageInfos); + delete app_images; + return stacks; +} +-(NSArray *)getOOMImageDataByUUID:(NSString *)uuid +{ + NSString *OOMDataPath = [[self OOMDataPath] stringByAppendingPathComponent:uuid]; + NSString *imagesDir = [OOMDataPath stringByAppendingPathComponent:@"app.images"]; + NSArray *imageData = [NSArray arrayWithContentsOfFile:imagesDir]; + if(imageData && [imageData isKindOfClass:[NSArray class]]){ + return imageData; + } + return nil; +} + +-(NSData *)getOOMMallocDataByUUID:(NSString *)uuid +{ + NSString *OOMDataPath = [[self OOMDataPath] stringByAppendingPathComponent:uuid]; + NSString *mallocPath = [OOMDataPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mmap",uuid]]; + NSData *rawData = [NSData dataWithContentsOfFile:mallocPath]; + if(rawData.length > 0){ + return rawData; + } + return nil; +} + +-(NSData *)getOOMVMDataByUUID:(NSString *)uuid +{ + NSString *OOMDataPath = [[self OOMDataPath] stringByAppendingPathComponent:uuid]; + NSString *vmPath = [OOMDataPath stringByAppendingPathComponent:[NSString stringWithFormat:@"vm_%@.mmap",uuid]]; + NSData *rawData = [NSData dataWithContentsOfFile:vmPath]; + if(rawData.length > 0){ + return rawData; + } + return nil; +} + + +-(void)removeOOMDataByUUID:(NSString *)uuid +{ + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *OOMDataPath = [[self OOMDataPath] stringByAppendingPathComponent:uuid]; + [fm removeItemAtPath:OOMDataPath error:nil]; +} + +-(void)clearOOMLog +{ + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *OOMDataPath = [self OOMDataPath]; + NSArray *paths = [fm contentsOfDirectoryAtPath:OOMDataPath error:nil]; + for(NSString *path in paths){ + NSString *fullPath = [OOMDataPath stringByAppendingPathComponent:path]; + if(_currentDir == nil || ![fullPath isEqualToString:_currentDir]){ + [fm removeItemAtPath:fullPath error:nil]; + } } } @@ -370,7 +406,7 @@ -(NSString *)OOMDataPath { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString *LibDirectory = [paths objectAtIndex:0]; - return [LibDirectory stringByAppendingPathComponent:@"OOMDetector"]; + return [LibDirectory stringByAppendingPathComponent:@"OOMDetector_New"]; } -(NSString *)OOMZipPath @@ -432,5 +468,17 @@ - (void)setFileDataDelegate:(id)delegate [[QQLeakFileUploadCenter defaultCenter] setFileDataDelegate:delegate]; } +-(double)getOccupyMemory +{ + if(global_memory_zone != NULL){ + malloc_statistics_t stats; + malloc_zone_statistics(global_memory_zone, &stats); + return stats.size_in_use/1024.0/1024.0; + } + else { + return 0; + } +} + @end diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/stacktrack/OOMMemoryStackTracker.mm b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/stacktrack/OOMMemoryStackTracker.mm index d663820..8112b4c 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/stacktrack/OOMMemoryStackTracker.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/stacktrack/OOMMemoryStackTracker.mm @@ -18,13 +18,13 @@ #import "execinfo.h" #import "CStackHelper.h" -#import "HighSpeedLogger.h" #import "OOMDetector.h" #import "QQLeakMallocStackTracker.h" #import "OOMMemoryStackTracker.h" #import "QQLeakFileUploadCenter.h" #import "QQLeakDeviceInfo.h" #import "CommonMallocLogger.h" +#import #if __has_feature(objc_arc) #error This file must be compiled without ARC. Use -fno-objc-arc flag. @@ -60,7 +60,6 @@ void oom_malloc_logger(uint32_t type, uintptr_t arg1, uintptr_t arg2, uintptr_t if (global_oomdetector == NULL) { return; } - if (type & stack_logging_flag_zone) { type &= ~stack_logging_flag_zone; } @@ -70,28 +69,45 @@ void oom_malloc_logger(uint32_t type, uintptr_t arg1, uintptr_t arg2, uintptr_t } if (arg2 == result) { if(global_oomdetector->enableOOMMonitor){ - global_oomdetector->removeMallocStack((vm_address_t)arg2,OOMDetectorMode); - global_oomdetector->recordMallocStack(result, (uint32_t)arg3,NULL,2); + global_oomdetector->removeMallocStack((vm_address_t)arg2); + if(global_oomdetector->sampleFactor > 1){ + if(rand()%(global_oomdetector->sampleFactor) != 0 && arg3 < global_oomdetector->sampleThreshold){ + return; + } + } + global_oomdetector->recordMallocStack(result, (uint32_t)arg3,2); } return; } if (!arg2) { if(global_oomdetector->enableOOMMonitor){ - global_oomdetector->recordMallocStack(result, (uint32_t)arg3,NULL,2); + if(global_oomdetector->sampleFactor > 1){ + if(rand()%(global_oomdetector->sampleFactor) != 0 && arg3 < global_oomdetector->sampleThreshold){ + return; + } + } + global_oomdetector->recordMallocStack(result, (uint32_t)arg3,2); } return; } else { if(global_oomdetector->enableOOMMonitor){ - global_oomdetector->removeMallocStack((vm_address_t)arg2,OOMDetectorMode); - global_oomdetector->recordMallocStack(result, (uint32_t)arg3,NULL,2); - } + global_oomdetector->removeMallocStack((vm_address_t)arg2); + if(global_oomdetector->sampleFactor > 1){ + if(rand()%(global_oomdetector->sampleFactor) != 0 && arg3 < global_oomdetector->sampleThreshold){ + return; + } + } + global_oomdetector->recordMallocStack(result, (uint32_t)arg3,2); + }; return; } } else if (type == stack_logging_type_dealloc) { - if (!arg2) return; + if (!arg2) { + return; + } if(global_oomdetector->enableOOMMonitor){ - global_oomdetector->removeMallocStack((vm_address_t)arg2,OOMDetectorMode); + global_oomdetector->removeMallocStack((vm_address_t)arg2); } } else if((type & stack_logging_type_alloc) != 0){ @@ -99,7 +115,12 @@ void oom_malloc_logger(uint32_t type, uintptr_t arg1, uintptr_t arg2, uintptr_t global_oomdetector->get_chunk_stack((size_t)arg2); } if(global_oomdetector->enableOOMMonitor){ - global_oomdetector->recordMallocStack(result, (uint32_t)arg2,NULL,2); + if(global_oomdetector->sampleFactor > 1){ + if(rand()%(global_oomdetector->sampleFactor) != 0 && arg2 < global_oomdetector->sampleThreshold){ + return; + } + } + global_oomdetector->recordMallocStack(result, (uint32_t)arg2,2); } } } @@ -109,17 +130,19 @@ void oom_vm_logger(uint32_t type, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3 if(type & stack_logging_type_vm_allocate){ //vm_mmap or vm_allocate type = (type & ~stack_logging_type_vm_allocate); type = type >> 24; - if((type >= 1 && type <= 11) || type == 32 || arg2 == 0){ + if((type >= 1 && type <= 11) || type == 32 || arg2 == 0 || type == 35){ return; } - const char *flag = "unknown"; - if(type <= 89){ - flag = vm_flags[type]; - } - global_oomdetector->recordVMStack(vm_address_t(result), uint32_t(arg2), flag, 2); +// const char *flag = "unknown"; +// if(type <= 89){ +// flag = vm_flags[type]; +// } + global_oomdetector->recordVMStack(vm_address_t(result), uint32_t(arg2), 2); } else if(type & stack_logging_type_vm_deallocate){ //vm_deallocate or munmap - if((type >= 1 && type <= 11) || type == 32 || arg2 == 0){ + type = (type & ~stack_logging_type_vm_allocate); + type = type >> 24; + if((type >= 1 && type <= 11) || type == 32 || arg2 == 0 || type == 35){ return; } global_oomdetector->removeVMStack(vm_address_t(arg2)); diff --git a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/statistic/OOMStatisticsInfoCenter.mm b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/statistic/OOMStatisticsInfoCenter.mm index d5028f0..57b4f24 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/statistic/OOMStatisticsInfoCenter.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/OOMDetector/statistic/OOMStatisticsInfoCenter.mm @@ -78,7 +78,7 @@ -(void)startMemoryOverFlowMonitor:(double)overFlowLimit overflow_limit = overFlowLimit; _thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain) object:nil]; [_thread setName:@"MemoryOverflowMonitor"]; - _timer = [[NSTimer timerWithTimeInterval:0.03 target:self selector:@selector(updateMemory) userInfo:nil repeats:YES] retain]; + _timer = [[NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(updateMemory) userInfo:nil repeats:YES] retain]; [_thread start]; } @@ -106,11 +106,12 @@ -(void)updateMemory if (self.statisticsInfoBlock) { self.statisticsInfoBlock(_residentMemSize); } - _indicatorView.memory = _residentMemSize; + double physFootprintMemory = [self physFootprintMemory]; + _indicatorView.memory = _residentMemSize;//physFootprintMemory; + NSLog(@"resident:%lfMb footprint:%lfMb",_residentMemSize,physFootprintMemory); ++flag; if(maxMemory && flag >= 30){ if(maxMemory > _singleLoginMaxMemory){ -// NSLog(@"OOMStatisticsInfoCenter update maxMemory:%.2fMb",maxMemory); _singleLoginMaxMemory = maxMemory; [self saveLastSingleLoginMaxMemory]; flag = 0; @@ -194,6 +195,18 @@ - (double)appMaxMemory return taskInfo.resident_size_max / 1024.0 / 1024.0; } +- (double)physFootprintMemory{ + int64_t memoryUsageInByte = 0; + task_vm_info_data_t vmInfo; + mach_msg_type_number_t count = TASK_VM_INFO_COUNT; + kern_return_t kernelReturn = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count); + if(kernelReturn == KERN_SUCCESS) { + memoryUsageInByte = (int64_t) vmInfo.phys_footprint; + } + return (double)memoryUsageInByte/ 1024.0 / 1024.0; +} + + - (void)showMemoryIndicatorView:(BOOL)yn { if (yn) { diff --git a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/hook/AllocationTracker.mm b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/hook/AllocationTracker.mm index 95ae54c..d92c316 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/hook/AllocationTracker.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/hook/AllocationTracker.mm @@ -31,6 +31,7 @@ #import "QQLeakMallocStackTracker.h" #import "CObjcFilter.h" #import "CLeakChecker.h" +#import "NSObject+FOOMSwizzle.h" #if __has_feature(objc_arc) #error This file must be compiled without ARC. Use -fno-objc-arc flag. @@ -40,39 +41,6 @@ static AllocationTracker *tracker; -@interface NSObject(MethodSwizzling) -+ (BOOL)swizzleMethod:(SEL)origSel withMethod:(SEL)altSel; -+ (BOOL)swizzleClassMethod:(SEL)origSel withClassMethod:(SEL)altSel; - -@end - - -@implementation NSObject (MethodSwizzling) - -+ (BOOL)swizzleMethod:(SEL)origSel withMethod:(SEL)altSel -{ - Method originMethod = class_getInstanceMethod(self, origSel); - Method newMethod = class_getInstanceMethod(self, altSel); - if (originMethod && newMethod) { - //2012年5月更新 - if (class_addMethod(self, origSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) { - class_replaceMethod(self, altSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod)); - } else { - method_exchangeImplementations(originMethod, newMethod); - } - return YES; - } - return NO; -} - -+ (BOOL)swizzleClassMethod:(SEL)origSel withClassMethod:(SEL)altSel -{ - Class c = object_getClass((id)self); - return [c swizzleMethod:origSel withMethod:altSel]; -} - -@end - @interface NSObject(AllocationTracker) + (id)Tracker_Alloc; diff --git a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/hook/NSObject+FOOMSwizzle.h b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/hook/NSObject+FOOMSwizzle.h new file mode 100644 index 0000000..cfa14f8 --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/hook/NSObject+FOOMSwizzle.h @@ -0,0 +1,25 @@ +// NSObject+FOOMSwizzle.h +// QQLeak +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + +#import + +@interface NSObject (FOOMSwizzle) + ++ (BOOL)swizzleMethod:(SEL)origSel withMethod:(SEL)altSel; ++ (BOOL)swizzleClassMethod:(SEL)origSel withClassMethod:(SEL)altSel; + +@end diff --git a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/hook/NSObject+FOOMSwizzle.m b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/hook/NSObject+FOOMSwizzle.m new file mode 100644 index 0000000..e4a205d --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/hook/NSObject+FOOMSwizzle.m @@ -0,0 +1,44 @@ +// NSObject+FOOMSwizzle.m +// QQLeak +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + +#import "NSObject+FOOMSwizzle.h" +#import + +@implementation NSObject (FOOMSwizzle) + ++ (BOOL)swizzleMethod:(SEL)origSel withMethod:(SEL)altSel +{ + Method originMethod = class_getInstanceMethod(self, origSel); + Method newMethod = class_getInstanceMethod(self, altSel); + if (originMethod && newMethod) { + if (class_addMethod(self, origSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) { + class_replaceMethod(self, altSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod)); + } else { + method_exchangeImplementations(originMethod, newMethod); + } + return YES; + } + return NO; +} + ++ (BOOL)swizzleClassMethod:(SEL)origSel withClassMethod:(SEL)altSel +{ + Class c = object_getClass((id)self); + return [c swizzleMethod:origSel withMethod:altSel]; +} + +@end diff --git a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/CLeakChecker.h b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/CLeakChecker.h index 3bf74c7..7298220 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/CLeakChecker.h +++ b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/CLeakChecker.h @@ -39,6 +39,7 @@ #import "QQLeakFileUploadCenter.h" #import "QQLeakDeviceInfo.h" #import "AllocationTracker.h" +#import "CLeakedStacksHashmap.h" #ifdef __IPHONE_10_0 #import #endif @@ -74,7 +75,7 @@ class CLeakChecker public: malloc_zone_t *getMemoryZone(); CPtrsHashmap *getPtrHashmap(); - CStacksHashmap *getStackHashmap(); + CLeakedStacksHashmap *getStackHashmap(); void setMaxStackDepth(size_t depth); void setNeedSysStack(BOOL need); size_t getMaxStackDepth(); @@ -88,12 +89,11 @@ class CLeakChecker void lockHashmap(); void lockThreadTracking(); void unlockThreadTracking(); - private: CLeakedHashmap *leaked_hashmap = NULL; CThreadTrackingHashmap *threadTracking_hashmap = NULL; CPtrsHashmap *qleak_ptrs_hashmap = NULL; - CStacksHashmap *qleak_stacks_hashmap = NULL; + CLeakedStacksHashmap *qleak_stacks_hashmap = NULL; CObjcFilter *objcFilter = NULL; malloc_zone_t *malloc_zone = NULL; CStackHelper *stackHelper = NULL; diff --git a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/CLeakChecker.mm b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/CLeakChecker.mm index 1fbfb76..0979df3 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/CLeakChecker.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/CLeakChecker.mm @@ -21,11 +21,12 @@ #import "CLeakChecker.h" #import "QQLeakChecker.h" #import "CommonMallocLogger.h" - +#import "RapidCRC.h" +#import "CLeakedStacksHashmap.h" CLeakChecker::CLeakChecker() { - stackHelper = new CStackHelper(); + stackHelper = new CStackHelper(nil); pthread_mutex_init(&hashmap_mutex,NULL); hashmap_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_init(&threadTracking_mutex,NULL); @@ -57,7 +58,7 @@ bool CLeakChecker::findPtrInMemoryRegion(vm_address_t address){ ptr_log_t *ptr_log = qleak_ptrs_hashmap->lookupPtr(address); if(ptr_log != NULL){ - ptr_log->refer++; + ptr_log->size++; return true; } return false; @@ -96,7 +97,8 @@ objcFilter = new CObjcFilter(); objcFilter->initBlackClass(); qleak_ptrs_hashmap = new CPtrsHashmap(100000,global_memory_zone); - qleak_stacks_hashmap = new CStacksHashmap(50000,global_memory_zone,QQLeakMode); + qleak_stacks_hashmap = new CLeakedStacksHashmap(50000,global_memory_zone); + init_crc_table_for_oom(); } void CLeakChecker::beginLeakChecker(){ @@ -158,21 +160,21 @@ void CLeakChecker::recordMallocStack(vm_address_t address,uint32_t size,const char*name,size_t stack_num_to_skip) { - base_stack_t base_stack; + base_leaked_stack_t base_stack; base_ptr_log base_ptr; - unsigned char md5[16]; + uint64_t digest; vm_address_t *stack[max_stack_depth]; - base_stack.depth = stackHelper->recordBacktrace(needSysStack,0,stack_num_to_skip + 1, stack,md5,max_stack_depth); - + base_stack.depth = stackHelper->recordBacktrace(needSysStack,0,0,stack_num_to_skip + 1, stack,&digest,max_stack_depth); if(base_stack.depth > 0){ base_stack.stack = stack; base_stack.extra.name = name; - base_ptr.md5 = md5; - base_ptr.size = size; + base_stack.extra.size = size; + base_ptr.digest = digest; + base_ptr.size = 0; lockHashmap(); if(qleak_ptrs_hashmap && qleak_stacks_hashmap){ if(qleak_ptrs_hashmap->insertPtr(address, &base_ptr)){ - qleak_stacks_hashmap->insertStackAndIncreaseCountIfExist(md5, &base_stack); + qleak_stacks_hashmap->insertStackAndIncreaseCountIfExist(digest, &base_stack); } } unlockHashmap(); @@ -183,15 +185,10 @@ { lockHashmap(); if(qleak_ptrs_hashmap && qleak_stacks_hashmap){ - ptr_log_t *ptr_log = qleak_ptrs_hashmap->lookupPtr(address); - if(ptr_log != NULL) - { - unsigned char md5[16]; - strncpy((char *)md5, (const char *)ptr_log->md5, 16); - size_t size = (size_t)ptr_log->size; - if(qleak_ptrs_hashmap->removePtr(address)){ - qleak_stacks_hashmap->removeIfCountIsZero(md5,size); - } + uint32_t size = 0; + uint64_t digest = 0; + if(qleak_ptrs_hashmap->removePtr(address,&size,&digest)){ + qleak_stacks_hashmap->removeIfCountIsZero(digest,size); } } unlockHashmap(); @@ -204,30 +201,33 @@ base_entry_t *entry = qleak_ptrs_hashmap->getHashmapEntry() + i; ptr_log_t *current = (ptr_log_t *)entry->root; while(current != NULL){ - merge_stack_t *merge_stack = qleak_stacks_hashmap->lookupStack(current->md5); + merge_leaked_stack_t *merge_stack = qleak_stacks_hashmap->lookupStack(current->digest); if(merge_stack == NULL) { current = current->next; continue; } if(merge_stack->extra.name != NULL){ - if(current->refer == 0){ - leaked_hashmap->insertLeakPtrAndIncreaseCountIfExist(current->md5, current); - qleak_ptrs_hashmap->removePtr(current->address); + if(current->size == 0){ + leaked_hashmap->insertLeakPtrAndIncreaseCountIfExist(current->digest, current); + vm_address_t address = current->address; + qleak_ptrs_hashmap->removePtr(address,NULL,NULL); } - current->refer = 0; + current->size = 0; } else{ - const char* name = objcFilter->getObjectNameExceptBlack((void *)current->address); + vm_address_t address = current->address; + const char* name = objcFilter->getObjectNameExceptBlack((void *)address); if(name != NULL){ - merge_stack->extra.name = name; - if(current->refer == 0){ - leaked_hashmap->insertLeakPtrAndIncreaseCountIfExist(current->md5, current); - qleak_ptrs_hashmap->removePtr(current->address); + if(current->size == 0){ + merge_stack->extra.name = name; + leaked_hashmap->insertLeakPtrAndIncreaseCountIfExist(current->digest, current); + vm_address_t address = (vm_address_t)(0x100000000 | current->address); + qleak_ptrs_hashmap->removePtr(address,NULL,NULL); } - current->refer = 0; + current->size = 0; } else { - qleak_ptrs_hashmap->removePtr(current->address); + qleak_ptrs_hashmap->removePtr(current->address,NULL,NULL); } } current = current->next; @@ -244,7 +244,7 @@ base_entry_t *entry = leaked_hashmap->getHashmapEntry() + i; leaked_ptr_t *current = (leaked_ptr_t *)entry->root; while(current != NULL){ - merge_stack_t *merge_stack = qleak_stacks_hashmap->lookupStack(current->md5); + merge_leaked_stack_t *merge_stack = qleak_stacks_hashmap->lookupStack(current->digest); if(merge_stack == NULL) { current = current->next; continue; @@ -275,6 +275,7 @@ void CLeakChecker::uploadLeakData(NSString *leakStr) { + // NSLog(@"%@",leakStr); if ([QQLeakFileUploadCenter defaultCenter].fileDataDelegate) { NSMutableString *leakData = [[[NSMutableString alloc] initWithString:leakStr] autorelease]; [leakData insertString:[NSString stringWithFormat:@"QQLeak montitor: os:%@, device_type:%@\n", [[NSProcessInfo processInfo] operatingSystemVersionString], [QQLeakDeviceInfo platform]] atIndex:0]; @@ -316,7 +317,7 @@ return qleak_ptrs_hashmap; } -CStacksHashmap *CLeakChecker::getStackHashmap() +CLeakedStacksHashmap *CLeakChecker::getStackHashmap() { return qleak_stacks_hashmap; } diff --git a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/QQLeakChecker.mm b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/QQLeakChecker.mm index b4e1555..0f10365 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/QQLeakChecker.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/main/QQLeakChecker.mm @@ -27,12 +27,12 @@ #import "QQLeakPredefines.h" #import "CMallocHook.h" #import "CThreadTrackingHashmap.h" -#import "CStacksHashmap.h" #import "CPtrsHashmap.h" #import "CLeakedHashmap.h" #import "CObjcFilter.h" #import #import "CLeakChecker.h" +#import "CLeakedStacksHashmap.h" #if __has_feature(objc_arc) #error This file must be compiled without ARC. Use -fno-objc-arc flag. @@ -138,7 +138,7 @@ -(size_t)getRecordObjNumber -(size_t)getRecordStackNumber { - return global_leakChecker->getStackHashmap()->getRecordNum(); + return global_leakChecker->getPtrHashmap()->getRecordNum(); } @end diff --git a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedHashmap.h b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedHashmap.h index f2c4432..c0a1824 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedHashmap.h +++ b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedHashmap.h @@ -23,7 +23,7 @@ #import "CPtrsHashmap.h" typedef struct leaked_ptr_t{ - unsigned char md5[16]; + uint64_t digest; uint32_t leak_count; vm_address_t address; leaked_ptr_t *next; @@ -33,12 +33,12 @@ class CLeakedHashmap : public CBaseHashmap { public: CLeakedHashmap(size_t entrys,malloc_zone_t *memory_zone):CBaseHashmap(entrys,memory_zone){}; - void insertLeakPtrAndIncreaseCountIfExist(unsigned char *md5,ptr_log_t *ptr_log); + void insertLeakPtrAndIncreaseCountIfExist(uint64_t digest,ptr_log_t *ptr_log); ~CLeakedHashmap(); protected: - leaked_ptr_t *create_hashmap_data(unsigned char *md5,ptr_log_t *ptr_log); - int compare(leaked_ptr_t *leak_ptr,unsigned char *md5); - size_t hash_code(void *key); + leaked_ptr_t *create_hashmap_data(uint64_t digest,ptr_log_t *ptr_log); + int compare(leaked_ptr_t *leak_ptr,uint64_t digest); + size_t hash_code(uint64_t digest); }; #endif /* CMergedHashmap_h */ diff --git a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedHashmap.mm b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedHashmap.mm index a6ae123..0dce361 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedHashmap.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedHashmap.mm @@ -37,21 +37,21 @@ } } -void CLeakedHashmap::insertLeakPtrAndIncreaseCountIfExist(unsigned char *md5,ptr_log_t *ptr_log) +void CLeakedHashmap::insertLeakPtrAndIncreaseCountIfExist(uint64_t digest,ptr_log_t *ptr_log) { - size_t offset = hash_code(md5); + size_t offset = hash_code(digest); base_entry_t *entry = hashmap_entry + offset; leaked_ptr_t *parent = (leaked_ptr_t *)entry->root; access_num++; collision_num++; if(parent == NULL){ - leaked_ptr_t *insert_data = create_hashmap_data(md5,ptr_log); + leaked_ptr_t *insert_data = create_hashmap_data(digest,ptr_log); entry->root = insert_data; record_num++; return ; } else{ - if(compare(parent,md5) == 0){ + if(compare(parent,digest) == 0){ parent->leak_count++; parent->address = ptr_log->address; return; @@ -59,7 +59,7 @@ leaked_ptr_t *current = parent->next; while(current != NULL){ collision_num++; - if(compare(current,md5) == 0){ + if(compare(current,digest) == 0){ current->leak_count++; current->address = ptr_log->address; return ; @@ -67,34 +67,32 @@ parent = current; current = current->next; } - leaked_ptr_t *insert_data = create_hashmap_data(md5,ptr_log); + leaked_ptr_t *insert_data = create_hashmap_data(digest,ptr_log); parent->next = insert_data; record_num++; return; } } -leaked_ptr_t *CLeakedHashmap::create_hashmap_data(unsigned char *md5,ptr_log_t *ptr_log) +leaked_ptr_t *CLeakedHashmap::create_hashmap_data(uint64_t digest,ptr_log_t *ptr_log) { leaked_ptr_t *leak_ptr = (leaked_ptr_t *)hashmap_malloc(sizeof(leaked_ptr_t)); - memcpy(leak_ptr->md5,md5,16*sizeof(char)); - leak_ptr->address = ptr_log->address; + leak_ptr->digest = digest; + vm_address_t address = (vm_address_t)(0x100000000 | ptr_log->address); + leak_ptr->address = address; leak_ptr->leak_count = 1; leak_ptr->next = NULL; return leak_ptr; } -int CLeakedHashmap::compare(leaked_ptr_t *leak_ptr,unsigned char *md5) +int CLeakedHashmap::compare(leaked_ptr_t *leak_ptr,uint64_t digest) { - unsigned char *md5_1 = leak_ptr->md5; - if(strncmp((char *)md5_1,(char *)md5,16)== 0) return 0; + if(leak_ptr->digest == digest) return 0; return -1; } -size_t CLeakedHashmap::hash_code(void *key) +size_t CLeakedHashmap::hash_code(uint64_t digest) { - uint64_t *value_1 = (uint64_t *)key; - uint64_t *value_2 = value_1 + 1; - size_t offset = (size_t)(*value_1 + *value_2)%(entry_num - 1); + size_t offset = (size_t)digest%(entry_num - 1); return offset; } diff --git a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedStacksHashmap.h b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedStacksHashmap.h new file mode 100644 index 0000000..7dd10ce --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedStacksHashmap.h @@ -0,0 +1,58 @@ +// +// CLeakedStacksHashmap.h +// QQLeak +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + +#ifndef CLeakedStacksHashmap_h +#define CLeakedStacksHashmap_h + +#import "CBaseHashmap.h" + +typedef struct extra_t{ + const char *name; + uint32_t size; +}extra_t; + +typedef struct base_leaked_stack_t{ + uint16_t depth; + vm_address_t **stack; + extra_t extra; +}base_leaked_stack_t; + +typedef struct merge_leaked_stack_t{ + uint64_t digest; + uint32_t depth; + uint32_t count; + vm_address_t **stack; + merge_leaked_stack_t *next; + extra_t extra; +} merge_leaked_stack_t; + +class CLeakedStacksHashmap : public CBaseHashmap +{ +public: + CLeakedStacksHashmap(size_t entrys,malloc_zone_t *memory_zone); + void insertStackAndIncreaseCountIfExist(uint64_t digest,base_leaked_stack_t *stack); + void removeIfCountIsZero(uint64_t digest, size_t size); + merge_leaked_stack_t *lookupStack(uint64_t digest); + ~CLeakedStacksHashmap(); +public: + size_t oom_threshold; +protected: + merge_leaked_stack_t *create_hashmap_data(uint64_t digest,base_leaked_stack_t *stack); +}; + +#endif /* CMergestackHashmap_h */ diff --git a/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedStacksHashmap.mm b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedStacksHashmap.mm new file mode 100644 index 0000000..6393ced --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/QQLeak/structures/CLeakedStacksHashmap.mm @@ -0,0 +1,180 @@ +// +// CLeakedStacksHashmap.mm +// QQLeak +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + +#import "CLeakedStacksHashmap.h" +#import "QQLeakMallocStackTracker.h" + +#if __has_feature(objc_arc) +#error This file must be compiled without ARC. Use -fno-objc-arc flag. +#endif + +CLeakedStacksHashmap::CLeakedStacksHashmap(size_t entrys,malloc_zone_t *zone):CBaseHashmap(entrys,zone) +{ + +} + +CLeakedStacksHashmap::~CLeakedStacksHashmap() +{ + for(size_t i = 0; i < entry_num; i++){ + base_entry_t *entry = hashmap_entry + i; + merge_leaked_stack_t *current = (merge_leaked_stack_t *)entry->root; + entry->root = NULL; + while(current != NULL){ + merge_leaked_stack_t *next = current->next; + if(current->stack != NULL){ + hashmap_free(current->stack); + } + hashmap_free(current); + current = next; + } + } +} + +void CLeakedStacksHashmap::insertStackAndIncreaseCountIfExist(uint64_t digest,base_leaked_stack_t *stack) +{ + size_t offset = (size_t)digest%(entry_num - 1); + base_entry_t *entry = hashmap_entry + offset; + merge_leaked_stack_t *parent = (merge_leaked_stack_t *)entry->root; + access_num++; + collision_num++; + if(parent == NULL){ + merge_leaked_stack_t *insert_data = create_hashmap_data(digest,stack); + entry->root = insert_data; + record_num++; + return ; + } + else{ + if(parent->digest == digest){ + parent->count++; + parent->extra.name = stack->extra.name; + parent->extra.size += stack->extra.size; + if(parent->stack == NULL) + { + parent->stack = (vm_address_t **)hashmap_malloc(stack->depth*sizeof(vm_address_t*)); + memcpy(parent->stack, stack->stack, stack->depth * sizeof(vm_address_t *)); + parent->depth = stack->depth; + } + return; + } + merge_leaked_stack_t *current = parent->next; + while(current != NULL){ + collision_num++; + if(current->digest == digest){ + current->count++; + current->extra.name = stack->extra.name; + current->extra.size += stack->extra.size; + if(current->stack == NULL) + { + current->stack = (vm_address_t **)hashmap_malloc(stack->depth*sizeof(vm_address_t*)); + memcpy(current->stack, stack->stack, stack->depth * sizeof(vm_address_t *)); + current->depth = stack->depth; + } + return ; + } + parent = current; + current = current->next; + } + merge_leaked_stack_t *insert_data = create_hashmap_data(digest,stack); + parent->next = insert_data; + record_num++; + return ; + } +} + +void CLeakedStacksHashmap::removeIfCountIsZero(uint64_t digest,size_t size) +{ + size_t offset = (size_t)digest%(entry_num - 1); + base_entry_t *entry = hashmap_entry + offset; + merge_leaked_stack_t *parent = (merge_leaked_stack_t *)entry->root; + if(parent == NULL){ + return ; + } + else{ + if(parent->digest == digest){ + if(parent->extra.size < size) parent->extra.size = 0; + else parent->extra.size -= size; + if(--(parent->count) <= 0 || parent->extra.size == 0) + { + entry->root = parent->next; + if(parent->stack != NULL){ + hashmap_free(parent->stack); + } + hashmap_free(parent); + record_num--; + } + return ; + } + merge_leaked_stack_t *current = parent->next; + while(current != NULL){ + if(current->digest == digest){ + if(current->extra.size < size) current->extra.size = 0; + else current->extra.size -= size; + if(--(current->count) <= 0 || current->extra.size == 0) + { + parent->next = current->next; + if(current->stack != NULL){ + hashmap_free(current->stack); + } + hashmap_free(current); + record_num--; + } + return ; + } + parent = current; + current = current->next; + } + } +} + +merge_leaked_stack_t *CLeakedStacksHashmap::lookupStack(uint64_t digest) +{ + size_t offset = (size_t)digest%(entry_num - 1); + base_entry_t *entry = hashmap_entry + offset; + merge_leaked_stack_t *parent = (merge_leaked_stack_t *)entry->root; + if(parent == NULL){ + return NULL; + } + else{ + if(parent->digest == digest){ + return parent; + } + merge_leaked_stack_t *current = parent->next; + while(current != NULL){ + if(current->digest == digest){ + return current; + } + parent = current; + current = current->next; + } + } + return NULL; +} + +merge_leaked_stack_t *CLeakedStacksHashmap::create_hashmap_data(uint64_t digest,base_leaked_stack_t *base_stack) +{ + merge_leaked_stack_t *merge_data = (merge_leaked_stack_t *)hashmap_malloc(sizeof(merge_leaked_stack_t)); + merge_data->digest = digest; + merge_data->count = 1; + merge_data->extra.name = base_stack->extra.name; + merge_data->stack = (vm_address_t **)hashmap_malloc(base_stack->depth*sizeof(vm_address_t*)); + memcpy(merge_data->stack, base_stack->stack, base_stack->depth * sizeof(vm_address_t *)); + merge_data->depth = base_stack->depth; + merge_data->next = NULL; + return merge_data; +} + diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/QQLeakPredefines.h b/libOOMDetector/libOOMDetector/OOMDetector/common/QQLeakPredefines.h index 153bad4..4a21178 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/common/QQLeakPredefines.h +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/QQLeakPredefines.h @@ -77,6 +77,7 @@ typedef struct section section_t; #define stack_logging_flag_cleared 64 /* for NewEmptyHandle */ #define stack_logging_type_mapped_file_or_shared_mem 128 -#define max_stack_depth_sys 100 +#define max_stack_depth_sys 64 +#define md5_length 8 #endif /* QQLeakpredefines_h */ diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/stack/CStackHelper.h b/libOOMDetector/libOOMDetector/OOMDetector/common/stack/CStackHelper.h index de1485f..b186508 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/common/stack/CStackHelper.h +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/stack/CStackHelper.h @@ -32,6 +32,7 @@ #import "CBaseHashmap.h" #import "CStacksHashmap.h" #import "CPtrsHashmap.h" +#import typedef struct { @@ -50,11 +51,15 @@ typedef struct AppImages class CStackHelper { public: - CStackHelper(); + CStackHelper(NSString *saveDir); ~CStackHelper(); + static AppImages* parseImages(NSArray *imageArray); + static bool parseAddrOfImages(AppImages *images,vm_address_t addr,segImageInfo *image); bool isInAppAddress(vm_address_t addr); bool getImageByAddr(vm_address_t addr,segImageInfo *image); - size_t recordBacktrace(BOOL needSystemStack,size_t needAppStackCount,size_t backtrace_to_skip, vm_address_t **app_stack,unsigned char *md5,size_t max_stack_depth); + size_t recordBacktrace(BOOL needSystemStack,uint32_t type ,size_t needAppStackCount,size_t backtrace_to_skip, vm_address_t **app_stack,uint64_t *digest,size_t max_stack_depth); +private: + void saveImages(NSString *saveDir); private: AppImages allImages; }; diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/stack/CStackHelper.mm b/libOOMDetector/libOOMDetector/OOMDetector/common/stack/CStackHelper.mm index e14e50b..2fd8cf0 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/common/stack/CStackHelper.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/stack/CStackHelper.mm @@ -17,11 +17,21 @@ // #import "CStackHelper.h" +#import "RapidCRC.h" +#import "CommonMallocLogger.h" #if __has_feature(objc_arc) #error This file must be compiled without ARC. Use -fno-objc-arc flag. #endif +typedef struct +{ + vm_address_t beginAddr; + vm_address_t endAddr; +}App_Address; + +static App_Address app_addrs[3]; + CStackHelper::~CStackHelper() { for (size_t i = 0; i < allImages.size; i++) @@ -33,7 +43,7 @@ allImages.size = 0; } -CStackHelper::CStackHelper() +CStackHelper::CStackHelper(NSString *saveDir) { uint32_t count = _dyld_image_count(); allImages.imageInfos =(segImageInfo **)malloc(count*sizeof(segImageInfo*)); @@ -47,7 +57,7 @@ name = tmp + 1; } long offset = (long)header + sizeof(mach_header_t); - for (unsigned int i = 0; i < header->ncmds; i++) { + for (unsigned int j = 0; j < header->ncmds; j++) { const segment_command_t* segment = (const segment_command_t*)offset; if (segment->cmd == MY_SEGMENT_CMD_TYPE && strcmp(segment->segname, SEG_TEXT) == 0) { long begin = (long)segment->vmaddr + slide; @@ -57,16 +67,89 @@ image->beginAddr = begin; image->endAddr = end; image->name = name; +#ifdef build_for_QQ + static int index = 0; + if((strcmp(name, "TlibDy") == 0 || strcmp(name, "QQMainProject") == 0 || strcmp(name, "QQStoryCommon") == 0) && index < 3) + { + app_addrs[index].beginAddr = image->beginAddr; + app_addrs[index++].endAddr = image->endAddr; + } +#else + if(i == 0){ + app_addrs[0].beginAddr = image->beginAddr; + app_addrs[0].endAddr = image->endAddr; + } +#endif allImages.imageInfos[allImages.size++] = image; break; } offset += segment->cmdsize; } } + if(saveDir){ + saveImages(saveDir); + } +} + +void CStackHelper::saveImages(NSString *saveDir) +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease]; + for (size_t i = 0; i < allImages.size; i++) + { + NSString *imageName = [NSString stringWithCString:allImages.imageInfos[i]->name encoding:NSUTF8StringEncoding]; + NSDictionary *app_image = [NSDictionary dictionaryWithObjectsAndKeys:imageName,@"name",[NSNumber numberWithInteger:allImages.imageInfos[i]->beginAddr],@"beginAddr",[NSNumber numberWithInteger:allImages.imageInfos[i]->endAddr],@"endAddr",nil]; + [result addObject:app_image]; + } + NSString *save_path = [saveDir stringByAppendingPathComponent:@"app.images"]; + [result writeToFile:save_path atomically:YES]; + }); +} + +AppImages* CStackHelper::parseImages(NSArray *imageArray) +{ + AppImages *result = new AppImages(); + result->size = 0; + result->imageInfos = (segImageInfo **)malloc([imageArray count]*sizeof(segImageInfo*)); + for(NSDictionary *image in imageArray){ + NSNumber *beginAddr = [image objectForKey:@"beginAddr"]; + NSNumber *endAddr = [image objectForKey:@"endAddr"]; + NSString *name = [image objectForKey:@"name"]; + if(beginAddr && endAddr && name){ + segImageInfo *image = (segImageInfo *)malloc(sizeof(segImageInfo)); + image->loadAddr = [beginAddr integerValue]; + image->beginAddr = [beginAddr integerValue];; + image->endAddr = [endAddr integerValue];; + image->name = [name UTF8String]; + result->imageInfos[result->size++] = image; + } + } + return result; +} + +bool CStackHelper::parseAddrOfImages(AppImages *images,vm_address_t addr,segImageInfo *image){ + for (size_t i = 0; i < images->size; i++) + { + if (addr > images->imageInfos[i]->beginAddr && addr < images->imageInfos[i]->endAddr) { + image->name = images->imageInfos[i]->name; + image->loadAddr = images->imageInfos[i]->loadAddr; + image->beginAddr = images->imageInfos[i]->beginAddr; + image->endAddr = images->imageInfos[i]->endAddr; + return true; + } + } + return false; } bool CStackHelper::isInAppAddress(vm_address_t addr){ - if(addr > allImages.imageInfos[0]->beginAddr && addr < allImages.imageInfos[0]->endAddr) return true; + if((addr >= app_addrs[0].beginAddr && addr < app_addrs[0].endAddr) +#ifdef build_for_QQ + || (addr >= app_addrs[1].beginAddr && addr < app_addrs[1].endAddr) || (addr >= app_addrs[2].beginAddr && addr < app_addrs[2].endAddr) +#endif + ) + { + return true; + } return false; } @@ -84,47 +167,54 @@ return false; } -size_t CStackHelper::recordBacktrace(BOOL needSystemStack,size_t needAppStackCount,size_t backtrace_to_skip, vm_address_t **app_stack,unsigned char *md5,size_t max_stack_depth) +size_t CStackHelper::recordBacktrace(BOOL needSystemStack,uint32_t type ,size_t needAppStackCount,size_t backtrace_to_skip, vm_address_t **app_stack,uint64_t *digest,size_t max_stack_depth) { - CC_MD5_CTX mc; - CC_MD5_Init(&mc); vm_address_t *orig_stack[max_stack_depth_sys]; size_t depth = backtrace((void**)orig_stack, max_stack_depth_sys); - size_t appstack_count = 0; + size_t orig_depth = depth; + if(depth > max_stack_depth){ + depth = max_stack_depth; + } + uint32_t compress_stacks[max_stack_depth_sys] = {'\0'}; size_t offset = 0; - vm_address_t *last_stack = NULL; - for(size_t i = backtrace_to_skip;i < depth;i++){ - if(appstack_count == 0){ - if(isInAppAddress((vm_address_t)orig_stack[i])){ - if(i < depth - 2) { - appstack_count++; - } - if(last_stack != NULL){ - app_stack[offset++] = last_stack; - } - app_stack[offset++] = orig_stack[i]; + size_t appstack_count = 0; + if(depth <= 3 + backtrace_to_skip){ + return 0; + } + size_t real_length = depth - 2 - backtrace_to_skip; + size_t index = 0; + compress_stacks[index++] = type; + for(size_t j = backtrace_to_skip;j < backtrace_to_skip + real_length;j++){ + if(needAppStackCount != 0){ + if(isInAppAddress((vm_address_t)orig_stack[j])){ + appstack_count++; + app_stack[offset++] = orig_stack[j]; + compress_stacks[index++] = (uint32_t)(uint64_t)orig_stack[j]; } else { if(needSystemStack){ - app_stack[offset++] = orig_stack[i]; - } - else { - last_stack = orig_stack[i]; + app_stack[offset++] = orig_stack[j]; + compress_stacks[index++] = (uint32_t)(uint64_t)orig_stack[j]; } } - if(offset >= max_stack_depth) break; } else{ - if(isInAppAddress((vm_address_t)orig_stack[i]) || i == depth -1 || needSystemStack) - { - if(i != depth - 2) appstack_count++; - app_stack[offset++] = orig_stack[i]; - } - if(offset >= max_stack_depth) break; + app_stack[offset++] = orig_stack[j]; + compress_stacks[index++] = (uint32_t)(uint64_t)orig_stack[j]; } - CC_MD5_Update(&mc, &orig_stack[i], sizeof(void*)); } - CC_MD5_Final(md5, &mc); - if(appstack_count >= needAppStackCount) return offset; + app_stack[offset] = orig_stack[orig_depth - 2]; + if((needAppStackCount > 0 && appstack_count > 0) || (needAppStackCount == 0 && offset > 0)){ + size_t remainder = (index*4)%8; + size_t compress_len = index*4 + (remainder == 0 ? 0 : (8 - remainder)); + // CC_MD5(&compress_stacks,(CC_LONG)2*depth,md5); + // memcpy(md5, &compress_stacks, 16); + // uint8_t digest[CC_SHA1_DIGEST_LENGTH]; + // CC_SHA1(&compress_stacks,(CC_LONG)2*depth, md5); + uint64_t crc = 0; + crc = rapid_crc64(crc, (const char *)&compress_stacks, compress_len); + *digest = crc; + return offset + 1; + } return 0; } diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/stack/RapidCRC.c b/libOOMDetector/libOOMDetector/OOMDetector/common/stack/RapidCRC.c new file mode 100644 index 0000000..2b59474 --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/stack/RapidCRC.c @@ -0,0 +1,83 @@ +// +// RapidCRC.c +// OOMDetector +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + +#include "RapidCRC.h" + +#define POLY64REV 0x95AC9329AC4BC9B5ULL + +static uint64_t crc_table[8][256]; + +#ifdef __cplusplus +extern "C" { +#endif + + void init_crc_table_for_oom(void) + { + uint64_t c; + int n, k; + static int first = 1; + if(first){ + first = 0; + for (n = 0; n < 256; n++) + { + c = (uint64_t)n; + for (k = 0; k < 8; k++) + { + if (c & 1) + c = (c >> 1) ^ POLY64REV; + else + c >>= 1; + } + crc_table[0][n] = c; + } + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + for (k = 1; k < 8; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + } + } + } + } + + uint64_t rapid_crc64(uint64_t crc, const char *buf, uint64_t len) + { + register uint64_t *buf64 = (uint64_t *)buf; + register uint64_t c = crc; + register uint64_t length = len; + c = ~c; + while (length >= 8) { + c ^= *buf64++; + c = crc_table[0][c & 0xff] ^ crc_table[1][(c >> 8) & 0xff] ^ \ + crc_table[2][(c >> 16) & 0xff] ^ crc_table[3][(c >> 24) & 0xff] ^\ + crc_table[4][(c >> 32) & 0xff] ^ crc_table[5][(c >> 40) & 0xff] ^\ + crc_table[6][(c >> 48) & 0xff] ^ crc_table[7][(c >> 56) & 0xff]; + length -= 8; + } +// buf = (char *)buf64; +// while (length > 0) { +// crc = (crc >> 8) ^ crc_table[0][(crc & 0xff) ^ *buf++]; +// length--; +// } + c = ~c; + return c; + } + +#ifdef __cplusplus +} +#endif diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/stack/RapidCRC.h b/libOOMDetector/libOOMDetector/OOMDetector/common/stack/RapidCRC.h new file mode 100644 index 0000000..9896b3b --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/stack/RapidCRC.h @@ -0,0 +1,38 @@ +// +// RapidCRC.h +// OOMDetector +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + +#ifndef CRC64_h +#define CRC64_h + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + extern void init_crc_table_for_oom(void); + extern uint64_t rapid_crc64(uint64_t crc, const char *buf, uint64_t len); +// uint64_t crc64(uint64_t crc, const char *buf, uint64_t len); +// extern int32_t crc32(uint8_t *bytes); +#ifdef __cplusplus +} +#endif + +#endif /* CRC64_h */ diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CPtrsHashmap.h b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CPtrsHashmap.h index 1e572fb..61ac7fa 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CPtrsHashmap.h +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CPtrsHashmap.h @@ -22,14 +22,14 @@ #import "CBaseHashmap.h" typedef struct base_ptr_log{ - unsigned char *md5; - uint32_t size; + uint64_t digest; + uint64_t size; + uint64_t record_num; } base_ptr_log; typedef struct ptr_log_t{ - unsigned char md5[16]; - size_t size; - size_t refer; + uint64_t digest; + uint32_t size; vm_address_t address; ptr_log_t *next; } ptr_log_t; @@ -39,13 +39,13 @@ class CPtrsHashmap : public CBaseHashmap public: CPtrsHashmap(size_t entrys,malloc_zone_t *memory_zone):CBaseHashmap(entrys,memory_zone){}; BOOL insertPtr(vm_address_t addr,base_ptr_log *ptr_log); - BOOL removePtr(vm_address_t addr); + BOOL removePtr(vm_address_t addr,uint32_t *removeSize, uint64_t *removeDigest); ptr_log_t *lookupPtr(vm_address_t addr); ~CPtrsHashmap(); protected: ptr_log_t *create_hashmap_data(vm_address_t addr,base_ptr_log *base_ptr); - int compare(ptr_log_t *ptr_log,vm_address_t addr); - size_t hash_code(vm_address_t addr); +// int compare(ptr_log_t *ptr_log,vm_address_t addr); +// size_t hash_code(vm_address_t addr); }; #endif /* CPtrHashmap_h */ diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CPtrsHashmap.mm b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CPtrsHashmap.mm index 2c1de3b..d113967 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CPtrsHashmap.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CPtrsHashmap.mm @@ -38,7 +38,7 @@ BOOL CPtrsHashmap::insertPtr(vm_address_t addr,base_ptr_log *ptr_log) { - size_t offset = hash_code(addr); + size_t offset = addr%(entry_num - 1); base_entry_t *entry = hashmap_entry + offset; ptr_log_t *parent = (ptr_log_t *)entry->root; access_num++; @@ -50,13 +50,13 @@ return YES; } else{ - if(compare(parent,addr) == 0){ + if(parent->address == addr){ return NO; } ptr_log_t *current = parent->next; while(current != NULL){ collision_num++; - if(compare(current,addr) == 0){ + if(current->address == addr){ return NO; } parent = current; @@ -69,25 +69,33 @@ } } -BOOL CPtrsHashmap::removePtr(vm_address_t addr) +BOOL CPtrsHashmap::removePtr(vm_address_t addr, uint32_t *removeSize, uint64_t *removeDigest) { - size_t offset = hash_code(addr); + size_t offset = addr%(entry_num - 1); base_entry_t *entry = hashmap_entry + offset; ptr_log_t *parent = (ptr_log_t *)entry->root; if(parent == NULL){ return NO; } else{ - if(compare(parent,addr) == 0){ + if(parent->address == addr){ entry->root = parent->next; + if(removeSize && removeDigest){ + *removeSize = parent->size; + *removeDigest = parent->digest; + } hashmap_free(parent); record_num--; return YES; } ptr_log_t *current = parent->next; while(current != NULL){ - if(compare(current,addr) == 0){ + if(current->address == addr){ parent->next = current->next; + if(removeSize && removeDigest){ + *removeSize = current->size; + *removeDigest = current->digest; + } hashmap_free(current); record_num--; return YES; @@ -101,16 +109,16 @@ ptr_log_t *CPtrsHashmap::lookupPtr(vm_address_t addr) { - size_t offset = hash_code(addr); + size_t offset = addr%(entry_num - 1); base_entry_t *entry = hashmap_entry + offset; ptr_log_t *parent = (ptr_log_t *)entry->root; if(parent != NULL){ - if(compare(parent,addr) == 0){ + if(parent->address == addr){ return parent; } ptr_log_t *current = parent->next; while(current != NULL){ - if(compare(current,addr) == 0){ + if(current->address == addr){ return current; } parent = current; @@ -123,23 +131,23 @@ ptr_log_t *CPtrsHashmap::create_hashmap_data(vm_address_t addr,base_ptr_log *base_ptr) { ptr_log_t *ptr_log = (ptr_log_t *)hashmap_malloc(sizeof(ptr_log_t)); - memcpy(ptr_log->md5,base_ptr->md5,16*sizeof(char)); - ptr_log->refer = 0; - ptr_log->size = (size_t)base_ptr->size; + ptr_log->digest = base_ptr->digest; + ptr_log->size = (uint32_t)base_ptr->size; ptr_log->address = addr; ptr_log->next = NULL; return ptr_log; } -int CPtrsHashmap::compare(ptr_log_t *ptr_log,vm_address_t addr) -{ - vm_address_t addr1 = ptr_log->address; - if(addr1 == addr) return 0; - return -1; -} +//int CPtrsHashmap::compare(ptr_log_t *ptr_log,vm_address_t addr) +//{ +// vm_address_t addr1 = ptr_log->address; +// if(addr1 == addr) return 0; +// return -1; +//} + +//size_t CPtrsHashmap::hash_code(vm_address_t addr) +//{ +// size_t offset = addr%(entry_num - 1); +// return offset; +//} -size_t CPtrsHashmap::hash_code(vm_address_t addr) -{ - size_t offset = addr%(entry_num - 1); - return offset; -} diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStackHighSpeedLogger.h b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStackHighSpeedLogger.h new file mode 100644 index 0000000..922f503 --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStackHighSpeedLogger.h @@ -0,0 +1,46 @@ +// +// CStackHighSpeedLogger.h +// OOMDetector +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + +#import "CStacksHashmap.h" +#import + +typedef struct cache_stack_t{ + uint32_t count; + uint32_t size; + uint32_t type; //0:malloc 1:vm + uint32_t stack_depth; + uint64_t digest; + vm_address_t *stacks[64]; +} cache_stack_t; + +class CStackHighSpeedLogger +{ +public: + CStackHighSpeedLogger(size_t num,malloc_zone_t *memory_zone,NSString *path); + void updateStack(merge_stack_t *current,base_stack_t *stack); + void removeStack(merge_stack_t *current,bool needRemove); + ~CStackHighSpeedLogger(); +private: + cache_stack_t *mmap_ptr; + size_t mmap_size; + malloc_zone_t *memory_zone; + FILE *mmap_fp; + bool isFailed; + size_t entry_num; + size_t total_logger_cnt; +}; diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStackHighSpeedLogger.mm b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStackHighSpeedLogger.mm new file mode 100644 index 0000000..9119117 --- /dev/null +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStackHighSpeedLogger.mm @@ -0,0 +1,143 @@ +// +// CStackHighSpeedLogger.mm +// OOMDetector +// +// Tencent is pleased to support the open source community by making OOMDetector available. +// Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +// +// + +#import "CStackHighSpeedLogger.h" +#import + +CStackHighSpeedLogger::CStackHighSpeedLogger(size_t num,malloc_zone_t *memory_zone,NSString *path) +{ + entry_num = num; + mmap_size = entry_num*sizeof(cache_stack_t); + total_logger_cnt = 0; + isFailed = false; + FILE *fp = fopen ( [path fileSystemRepresentation] , "wb+" ) ; + if(fp != NULL){ + int ret = ftruncate(fileno(fp), mmap_size); + if(ret == -1){ + isFailed = true; + } + else { + fseek(fp, 0, SEEK_SET); + cache_stack_t *ptr = (cache_stack_t *)mmap(0, mmap_size, PROT_WRITE | PROT_READ, (MAP_FILE|MAP_SHARED), fileno(fp), 0); + memset(ptr, '\0', mmap_size); + if(ptr != NULL){ + mmap_ptr = ptr; + mmap_fp = fp; + } + else { + isFailed = true; + } + } + } + else { + isFailed = true; + } +} + +CStackHighSpeedLogger::~CStackHighSpeedLogger() +{ + if(mmap_ptr != NULL){ + munmap(mmap_ptr , mmap_size); + } +} + +void CStackHighSpeedLogger::updateStack(merge_stack_t *current,base_stack_t *stack) +{ + if(isFailed) return; + size_t offset = (size_t)current->digest%(entry_num - 1); + cache_stack_t *cache_stack = mmap_ptr + offset; + while (cache_stack->count != 0) { + if(cache_stack->digest != current->digest){ + if(++offset == entry_num){ + offset = 0; + } + cache_stack = mmap_ptr + offset; + } + else { + if(total_logger_cnt > 0){ + total_logger_cnt--; + } + break; + } + } + cache_stack->size = (uint32_t)current->size; + cache_stack->count = current->count; + cache_stack->type = stack->type; + cache_stack->stack_depth = stack->depth; + cache_stack->digest = current->digest; + memcpy(cache_stack->stacks, stack->stack, stack->depth * sizeof(vm_address_t)); + total_logger_cnt++; + if(total_logger_cnt > (entry_num - 2) && stack->type != 1){ + char *copy = (char *)memory_zone->malloc(memory_zone, mmap_size); + memcpy(copy, mmap_ptr, mmap_size); + munmap(mmap_ptr ,mmap_size); + size_t copy_size = mmap_size; + entry_num = 2*entry_num; + mmap_size = entry_num*sizeof(cache_stack_t); + int ret = ftruncate(fileno(mmap_fp), mmap_size); + if(ret == -1){ + memory_zone->free(memory_zone,copy); + isFailed = true; + } + else { + fseek(mmap_fp, 0, SEEK_SET); + mmap_ptr = (cache_stack_t *)mmap(0, mmap_size, PROT_WRITE | PROT_READ, (MAP_FILE|MAP_SHARED), fileno(mmap_fp), 0); + memset(mmap_ptr, '\0', mmap_size); + if(!mmap_ptr){ + memory_zone->free(memory_zone,copy); + isFailed = false; + } + else { + isFailed = true; + memcpy(mmap_ptr, copy, copy_size); + } + } + memory_zone->free(memory_zone,copy); + } +} + +void CStackHighSpeedLogger::removeStack(merge_stack_t *current,bool needRemove) +{ + if(isFailed) return; + size_t offset = (size_t)current->digest%(entry_num - 1); + size_t last_offset = (offset == 0) ? (entry_num - 1) : (offset - 1); + cache_stack_t *cache_stack = mmap_ptr + offset; + while (cache_stack->count != 0 && cache_stack->digest != current->digest) { + if(++offset == entry_num){ + offset = 0; + } + if(offset == last_offset){ + cache_stack = NULL; + break; + } + cache_stack = mmap_ptr + offset; + } + if(cache_stack != NULL && cache_stack->count != 0){ + if(needRemove){ + cache_stack->size = 0; + cache_stack->count = 0; + } + else { + cache_stack->size = current->size; + cache_stack->count = current->count; + } + if(total_logger_cnt > 0 && cache_stack->count == 0){ + total_logger_cnt--; + } + } +} diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStacksHashmap.h b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStacksHashmap.h index c6057a3..8e4d217 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStacksHashmap.h +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStacksHashmap.h @@ -21,48 +21,40 @@ #import "CBaseHashmap.h" -typedef struct extra_t{ - const char *name; - uint32_t size; -}extra_t; +class CStackHighSpeedLogger; typedef struct base_stack_t{ - uint16_t depth; + uint32_t depth; vm_address_t **stack; - extra_t extra; + uint32_t size; + uint32_t type; + uint32_t count; }base_stack_t; typedef struct merge_stack_t{ - unsigned char md5[16]; + uint64_t digest; uint32_t depth; uint32_t count; - vm_address_t **stack; + uint32_t cache_flag; + uint32_t size; merge_stack_t *next; - extra_t extra; } merge_stack_t; -typedef enum -{ - QQLeakMode = 1, - OOMDetectorMode -}monitor_mode; - - class CStacksHashmap : public CBaseHashmap { public: - CStacksHashmap(size_t entrys,malloc_zone_t *memory_zone,monitor_mode mode); - void insertStackAndIncreaseCountIfExist(unsigned char *md5,base_stack_t *stack); - void removeIfCountIsZero(unsigned char *md5, size_t size); - merge_stack_t *lookupStack(unsigned char *md5); - monitor_mode mode; + CStacksHashmap(size_t entrys,malloc_zone_t *memory_zone,NSString *path, size_t mmap_size); + void insertStackAndIncreaseCountIfExist(uint64_t digest,base_stack_t *stack); + void removeIfCountIsZero(uint64_t digest,uint32_t size,uint32_t count); + merge_stack_t *lookupStack(uint64_t digest); ~CStacksHashmap(); public: size_t oom_threshold; + bool is_vm = false; protected: - merge_stack_t *create_hashmap_data(unsigned char *md5,base_stack_t *stack); - int compare(merge_stack_t *stack,unsigned char *md5); - size_t hash_code(void *key); + merge_stack_t *create_hashmap_data(uint64_t digest,base_stack_t *stack); +private: + CStackHighSpeedLogger *logger; }; #endif /* CMergestackHashmap_h */ diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStacksHashmap.mm b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStacksHashmap.mm index 0c02a63..fce034e 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStacksHashmap.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/structure/CStacksHashmap.mm @@ -18,14 +18,15 @@ #import "CStacksHashmap.h" #import "QQLeakMallocStackTracker.h" +#import "CStackHighSpeedLogger.h" #if __has_feature(objc_arc) #error This file must be compiled without ARC. Use -fno-objc-arc flag. #endif -CStacksHashmap::CStacksHashmap(size_t entrys,malloc_zone_t *zone,monitor_mode monitorMode):CBaseHashmap(entrys,zone) +CStacksHashmap::CStacksHashmap(size_t entrys,malloc_zone_t *zone,NSString *path, size_t mmap_size):CBaseHashmap(entrys,zone) { - mode = monitorMode; + logger = new CStackHighSpeedLogger(500,zone,path); } CStacksHashmap::~CStacksHashmap() @@ -36,96 +37,107 @@ entry->root = NULL; while(current != NULL){ merge_stack_t *next = current->next; - if(current->stack != NULL){ - hashmap_free(current->stack); - } hashmap_free(current); current = next; } } + if(logger != NULL){ + delete logger; + } } -void CStacksHashmap::insertStackAndIncreaseCountIfExist(unsigned char *md5,base_stack_t *stack) +void CStacksHashmap::insertStackAndIncreaseCountIfExist(uint64_t digest,base_stack_t *stack) { - size_t offset = hash_code(md5); + size_t offset = (size_t)digest%(entry_num - 1); base_entry_t *entry = hashmap_entry + offset; merge_stack_t *parent = (merge_stack_t *)entry->root; access_num++; collision_num++; if(parent == NULL){ - merge_stack_t *insert_data = create_hashmap_data(md5,stack); + merge_stack_t *insert_data = create_hashmap_data(digest,stack); entry->root = insert_data; + if(insert_data->size > oom_threshold) + { + insert_data->cache_flag = 1; + logger->updateStack(insert_data, stack); + } record_num++; return ; } else{ - if(compare(parent,md5) == 0){ - parent->count++; - if(mode == QQLeakMode){ - parent->extra.name = stack->extra.name; - } - else { - parent->extra.name = stack->extra.name; - parent->extra.size += stack->extra.size; - if(parent->extra.size > oom_threshold && parent->stack == NULL) - { - parent->stack = (vm_address_t **)hashmap_malloc(stack->depth*sizeof(vm_address_t*)); - memcpy(parent->stack, stack->stack, stack->depth * sizeof(vm_address_t *)); - parent->depth = stack->depth; - } + if(parent->digest == digest){ + parent->count += stack->count; + parent->size += stack->size; + if(parent->size > oom_threshold) + { + parent->cache_flag = 1; + logger->updateStack(parent, stack); } return; } merge_stack_t *current = parent->next; while(current != NULL){ collision_num++; - if(compare(current,md5) == 0){ - current->count++; - if(mode == QQLeakMode){ - current->extra.name = stack->extra.name; - } - else { - current->extra.name = stack->extra.name; - current->extra.size += stack->extra.size; - if(current->extra.size > oom_threshold && current->stack == NULL) - { - current->stack = (vm_address_t **)hashmap_malloc(stack->depth*sizeof(vm_address_t*)); - memcpy(current->stack, stack->stack, stack->depth * sizeof(vm_address_t *)); - current->depth = stack->depth; - } + if(current->digest == digest){ + current->count += stack->count; + current->size += stack->size; + if(current->size > oom_threshold) + { + current->cache_flag = 1; + logger->updateStack(current, stack); } return ; } parent = current; current = current->next; } - merge_stack_t *insert_data = create_hashmap_data(md5,stack); + merge_stack_t *insert_data = create_hashmap_data(digest,stack); parent->next = insert_data; + current = parent->next; + if(current->size > oom_threshold) + { + current->cache_flag = 1; + logger->updateStack(current, stack); + } record_num++; return ; } } -void CStacksHashmap::removeIfCountIsZero(unsigned char *md5,size_t size) +void CStacksHashmap::removeIfCountIsZero(uint64_t digest,uint32_t size,uint32_t count) { - size_t offset = hash_code(md5); + size_t offset = (size_t)digest%(entry_num - 1); base_entry_t *entry = hashmap_entry + offset; merge_stack_t *parent = (merge_stack_t *)entry->root; if(parent == NULL){ return ; } else{ - if(compare(parent,md5) == 0){ - if(mode == OOMDetectorMode){ - if(parent->extra.size < size) parent->extra.size = 0; - else parent->extra.size -= size; + if(parent->digest == digest){ + if(parent->size < size) { + parent->size = 0; + } + else { + parent->size -= size; + } + if(parent->count < count){ + parent->count = 0; + } + else { + parent->count -= count; + } + if(parent->cache_flag == 1){ + if(parent->size < oom_threshold){ + logger->removeStack(parent,true); + parent->cache_flag = 0; + } + else { + logger->removeStack(parent,false); + } } - if(--(parent->count) <= 0 || (mode == OOMDetectorMode && parent->extra.size == 0)) + if(parent->count <= 0) { entry->root = parent->next; - if(parent->stack != NULL){ - hashmap_free(parent->stack); - } hashmap_free(parent); record_num--; } @@ -133,17 +145,33 @@ } merge_stack_t *current = parent->next; while(current != NULL){ - if(compare(current,md5) == 0){ - if(mode == OOMDetectorMode){ - if(current->extra.size < size) current->extra.size = 0; - else current->extra.size -= size; + if(current->digest == digest){ + if(current->size < size) + { + current->size = 0; } - if(--(current->count) <= 0 || (mode == OOMDetectorMode && current->extra.size == 0)) + else { - parent->next = current->next; - if(current->stack != NULL){ - hashmap_free(current->stack); + current->size -= size; + } + if(current->count < count){ + current->count = 0; + } + else { + current->count -= count; + } + if(current->cache_flag == 1){ + if(current->size < oom_threshold){ + logger->removeStack(current,true); + current->cache_flag = 0; + } + else { + logger->removeStack(current,false); } + } + if((current->count) <= 0) + { + parent->next = current->next; hashmap_free(current); record_num--; } @@ -155,21 +183,21 @@ } } -merge_stack_t *CStacksHashmap::lookupStack(unsigned char *md5) +merge_stack_t *CStacksHashmap::lookupStack(uint64_t digest) { - size_t offset = hash_code(md5); + size_t offset = (size_t)digest%(entry_num - 1); base_entry_t *entry = hashmap_entry + offset; merge_stack_t *parent = (merge_stack_t *)entry->root; if(parent == NULL){ return NULL; } else{ - if(compare(parent,md5) == 0){ + if(parent->digest == digest){ return parent; } merge_stack_t *current = parent->next; while(current != NULL){ - if(compare(current,md5) == 0){ + if(current->digest == digest){ return current; } parent = current; @@ -179,44 +207,15 @@ return NULL; } -merge_stack_t *CStacksHashmap::create_hashmap_data(unsigned char *md5,base_stack_t *base_stack) +merge_stack_t *CStacksHashmap::create_hashmap_data(uint64_t digest,base_stack_t *base_stack) { merge_stack_t *merge_data = (merge_stack_t *)hashmap_malloc(sizeof(merge_stack_t)); - memcpy(merge_data->md5,md5,16*sizeof(char)); - merge_data->count = 1; - BOOL needStack = NO; - if(mode == QQLeakMode){ - merge_data->extra.name = base_stack->extra.name; - needStack = YES; - } - else { - merge_data->extra.name = base_stack->extra.name; - merge_data->extra.size = base_stack->extra.size; - } - if(base_stack->extra.size > oom_threshold || mode == QQLeakMode){ - merge_data->stack = (vm_address_t **)hashmap_malloc(base_stack->depth*sizeof(vm_address_t*)); - memcpy(merge_data->stack, base_stack->stack, base_stack->depth * sizeof(vm_address_t *)); - merge_data->depth = base_stack->depth; - } - else { - merge_data->stack = NULL; - merge_data->depth = 0; - } + merge_data->digest = digest; + merge_data->count = base_stack->count; + merge_data->cache_flag = 0; + merge_data->size = base_stack->size; + merge_data->depth = 0; merge_data->next = NULL; return merge_data; } -int CStacksHashmap::compare(merge_stack_t *stack,unsigned char *md5) -{ - unsigned char *md5_1 = stack->md5; - if(strncmp((char *)md5_1,(char *)md5,16) == 0) return 0; - return -1; -} - -size_t CStacksHashmap::hash_code(void *key) -{ - uint64_t *value_1 = (uint64_t *)key; - uint64_t *value_2 = value_1 + 1; - size_t offset = (size_t)(*value_1 + *value_2)%(entry_num - 1); - return offset; -} diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/upload/QQLeakFileUploadCenter.h b/libOOMDetector/libOOMDetector/OOMDetector/common/upload/QQLeakFileUploadCenter.h index 536c772..8160359 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/common/upload/QQLeakFileUploadCenter.h +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/upload/QQLeakFileUploadCenter.h @@ -27,7 +27,7 @@ typedef enum : NSUInteger { @protocol QQOOMFileDataDelegate /** 在出现单次大块内存分配、检查到内存泄漏且时、调用uploadAllStack方法时触发回调 */ --(void)fileData:(NSData *)data extra:(NSDictionary *)extra type:(QQStackReportType)type completionHandler:(void (^)(BOOL))completionHandler; +-(void)fileData:(id)data extra:(NSDictionary *)extra type:(QQStackReportType)type completionHandler:(void (^)(BOOL))completionHandler; @end @@ -37,6 +37,6 @@ typedef enum : NSUInteger { @property (nonatomic, assign) id fileDataDelegate; --(void)fileData:(NSData *)data extra:(NSDictionary *)extra type:(QQStackReportType)type completionHandler:(void(^)(BOOL completed))completionHandler; +-(void)fileData:(id)data extra:(NSDictionary *)extra type:(QQStackReportType)type completionHandler:(void (^)(BOOL))completionHandler; @end diff --git a/libOOMDetector/libOOMDetector/OOMDetector/common/upload/QQLeakFileUploadCenter.mm b/libOOMDetector/libOOMDetector/OOMDetector/common/upload/QQLeakFileUploadCenter.mm index 71c71ac..91b393a 100644 --- a/libOOMDetector/libOOMDetector/OOMDetector/common/upload/QQLeakFileUploadCenter.mm +++ b/libOOMDetector/libOOMDetector/OOMDetector/common/upload/QQLeakFileUploadCenter.mm @@ -38,7 +38,7 @@ +(QQLeakFileUploadCenter *)defaultCenter{ return center; } --(void)fileData:(NSData *)data extra:(NSDictionary *)extra type:(QQStackReportType)type completionHandler:(void (^)(BOOL))completionHandler +-(void)fileData:(id)data extra:(NSDictionary *)extra type:(QQStackReportType)type completionHandler:(void (^)(BOOL))completionHandler { if(data){ if (self.fileDataDelegate && [self.fileDataDelegate respondsToSelector:@selector(fileData:extra:type:completionHandler:)]) { diff --git a/stack translate/translate_oom.py b/stack translate/translate_oom.py index 060545b..d2aea4f 100755 --- a/stack translate/translate_oom.py +++ b/stack translate/translate_oom.py @@ -24,6 +24,7 @@ def translate_stack(list): addr = list[i]; command = command + " %s" %(addr); result = os.popen(command).read(); + # print "%s" % (command); if result: print "atos success!" return result; @@ -132,22 +133,23 @@ def translate(begin,key,prefix): result_fo.write( ")\n"); print "end translate %s..." %(key); -if __name__ == '__main__': - print"Begin Translation......"; - dsym_path = sys.argv[1]; - leak_path = sys.argv[2]; - dsym_path = dsym_path + "/Contents/Resources/DWARF"; - files = os.listdir(dsym_path); - file_name = os.path.basename(leak_path); - app_name = files[0]; - dsym_path = os.path.join(dsym_path,app_name); - print "APP Name:%s" %(app_name); - leak_fo = open(leak_path,"r"); - max_length = 10000; - translated_file = file_name + "_translated.log"; - result_fo = open(translated_file,"w"); - Leak_log = leak_fo.read(); - translate(0,"stack:","Malloc_size:"); - print"end Translation......"; + +print"Begin Translation......"; +dsym_path = sys.argv[1]; +leak_path = sys.argv[2]; +dsym_path = dsym_path + "/Contents/Resources/DWARF"; +files = os.listdir(dsym_path); +file_name = os.path.basename(leak_path); +app_name = files[0]; +dsym_path = os.path.join(dsym_path,app_name); +#app_name = os.path.split("/"); +print "APP Name:%s" %(app_name); +leak_fo = open(leak_path,"r"); +max_length = 10000; +translated_file = file_name + "_translated.log"; +result_fo = open(translated_file,"w"); +Leak_log = leak_fo.read(); +translate(0,"stack:","Malloc_size:"); +print"end Translation......";