iOS 内存压力测试工具

3 阅读4分钟

MemoryBomber.h

//
//  MemoryBomber.h
//  内存压力测试工具
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface MemoryBomber : NSObject

/**
 * 单例实例
 */
+ (instancetype)sharedInstance;

/**
 * 快速分配内存,触发 didReceiveMemoryWarning
 * @param targetMB 目标内存大小(MB),建议 500-2000,根据设备而定
 * @param chunkSizeMB 每次分配的块大小(MB),默认 50MB
 */
- (void)explodeWithTargetMB:(NSUInteger)targetMB chunkSizeMB:(NSUInteger)chunkSizeMB;

/**
 * 便捷方法:使用默认参数快速触发内存警告
 * 默认分配 1000MB(1GB),每次 50MB
 */
- (void)explode;

/**
 * 渐进式分配内存,模拟内存泄漏场景
 * @param targetMB 目标内存
 * @param interval 每次分配的间隔(秒)
 */
- (void)explodeGraduallyWithTargetMB:(NSUInteger)targetMB interval:(NSTimeInterval)interval;

/**
 * 停止渐进式分配
 */
- (void)stopGradualExplosion;

/**
 * 释放所有分配的内存
 */
- (void)releaseAllMemory;

/**
 * 获取当前已分配的内存大小(MB)
 */
- (NSUInteger)allocatedMemoryMB;

@end

NS_ASSUME_NONNULL_END

MemoryBomber.m

//
//  MemoryBomber.m
//  内存压力测试工具
//

#import "MemoryBomber.h"
#import <mach/mach.h>
#import <UIKit/UIKit.h>

@interface MemoryBomber ()

// 持有所有分配的内存块,防止被释放
@property (nonatomic, strong) NSMutableArray<NSData *> *memoryChunks;

// 渐进式分配的计时器
@property (nonatomic, strong) NSTimer *gradualTimer;
@property (nonatomic, assign) NSUInteger gradualTargetMB;
@property (nonatomic, assign) NSUInteger gradualCurrentMB;

@end

@implementation MemoryBomber

#pragma mark - 单例

+ (instancetype)sharedInstance {
    static MemoryBomber *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _memoryChunks = [NSMutableArray array];
    }
    return self;
}

#pragma mark - 公共方法

- (void)explode {
    // 默认分配 1GB,每次 50MB
    [self explodeWithTargetMB:1000 chunkSizeMB:50];
}

- (void)explodeWithTargetMB:(NSUInteger)targetMB chunkSizeMB:(NSUInteger)chunkSizeMB {
    // 先打印当前内存状态
    [self logMemoryStatus:@"开始分配内存前"];
    
    NSUInteger chunkSize = chunkSizeMB * 1024 * 1024; // 转换为字节
    NSUInteger allocated = 0;
    
    NSLog(@"💣 MemoryBomber: 开始分配内存,目标 %lu MB,每块 %lu MB", 
          (unsigned long)targetMB, (unsigned long)chunkSizeMB);
    
    while (allocated < targetMB) {
        @autoreleasepool {
            // 分配内存并填充随机数据(防止被压缩/优化)
            NSMutableData *chunk = [NSMutableData dataWithLength:chunkSize];
            
            // 填充数据,确保内存真正被占用
            uint8_t *bytes = chunk.mutableBytes;
            for (NSUInteger i = 0; i < chunkSize; i += 4096) {
                bytes[i] = (uint8_t)(arc4random() % 256);
            }
            
            [self.memoryChunks addObject:chunk];
            allocated += chunkSizeMB;
            
            NSLog(@"📊 已分配: %lu MB", (unsigned long)allocated);
            
            // 短暂休眠,让系统有机会响应
            [NSThread sleepForTimeInterval:0.05];
        }
    }
    
    [self logMemoryStatus:@"内存分配完成"];
    NSLog(@"💣 MemoryBomber: 内存分配完成,等待系统触发 didReceiveMemoryWarning...");
}

- (void)explodeGraduallyWithTargetMB:(NSUInteger)targetMB interval:(NSTimeInterval)interval {
    [self stopGradualExplosion]; // 停止之前的计时器
    
    self.gradualTargetMB = targetMB;
    self.gradualCurrentMB = 0;
    
    NSLog(@"⏱️ MemoryBomber: 开始渐进式分配,目标 %lu MB,间隔 %.1f 秒", 
          (unsigned long)targetMB, interval);
    
    __weak typeof(self) weakSelf = self;
    self.gradualTimer = [NSTimer scheduledTimerWithTimeInterval:interval
                                                         repeats:YES
                                                           block:^(NSTimer * _Nonnull timer) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (!strongSelf) return;
        
        if (strongSelf.gradualCurrentMB >= strongSelf.gradualTargetMB) {
            [strongSelf stopGradualExplosion];
            NSLog(@"✅ 渐进式分配完成");
            return;
        }
        
        // 每次分配 20MB
        NSUInteger chunkSize = 20 * 1024 * 1024;
        NSMutableData *chunk = [NSMutableData dataWithLength:chunkSize];
        uint8_t *bytes = chunk.mutableBytes;
        for (NSUInteger i = 0; i < chunkSize; i += 4096) {
            bytes[i] = (uint8_t)(arc4random() % 256);
        }
        
        [strongSelf.memoryChunks addObject:chunk];
        strongSelf.gradualCurrentMB += 20;
        
        NSLog(@"📊 渐进式分配: %lu / %lu MB", 
              (unsigned long)strongSelf.gradualCurrentMB,
              (unsigned long)strongSelf.gradualTargetMB);
        [strongSelf logMemoryStatus:@"渐进分配中"];
    }];
}

- (void)stopGradualExplosion {
    [self.gradualTimer invalidate];
    self.gradualTimer = nil;
}

- (void)releaseAllMemory {
    [self.memoryChunks removeAllObjects];
    self.gradualCurrentMB = 0;
    NSLog(@"🧹 MemoryBomber: 已释放所有内存");
    [self logMemoryStatus:@"释放内存后"];
}

- (NSUInteger)allocatedMemoryMB {
    NSUInteger totalBytes = 0;
    for (NSData *chunk in self.memoryChunks) {
        totalBytes += chunk.length;
    }
    return totalBytes / (1024 * 1024);
}

#pragma mark - 私有方法

- (void)logMemoryStatus:(NSString *)label {
    struct mach_task_basic_info info;
    mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT;
    kern_return_t kerr = task_info(mach_task_self(),
                                   MACH_TASK_BASIC_INFO,
                                   (task_info_t)&info,
                                   &size);
    if (kerr == KERN_SUCCESS) {
        NSUInteger usedMB = info.resident_size / (1024 * 1024);
        NSLog(@"📊 [%@] 进程内存使用: %lu MB", label, (unsigned long)usedMB);
    }
}

@end

MemoryBomber+UsageExample.m

//
//  MemoryBomber+UsageExample.m
//  使用示例
//

/*
 * ============================================
 * 使用步骤:
 * ============================================
 * 
 * 1. 将 MemoryBomber.h 和 MemoryBomber.m 添加到项目中
 * 
 * 2. 在需要的地方导入头文件
 *    #import "MemoryBomber.h"
 * 
 * 3. 调用方法触发内存暴涨
 */

#pragma mark - 示例 1: 在 ViewController 中使用

#import "MemoryBomber.h"

@interface TestViewController : UIViewController
@end

@implementation TestViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 添加一个按钮来触发内存暴涨
    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
    [button setTitle:@"触发内存警告" forState:UIControlStateNormal];
    [button addTarget:self action:@selector(triggerMemoryWarning) 
     forControlEvents:UIControlEventTouchUpInside];
    button.frame = CGRectMake(100, 200, 200, 50);
    [self.view addSubview:button];
}

- (void)triggerMemoryWarning {
    // 方式 1: 快速分配 1GB 内存
    [[MemoryBomber sharedInstance] explode];
    
    // 方式 2: 指定目标大小和块大小
    // [[MemoryBomber sharedInstance] explodeWithTargetMB:1500 chunkSizeMB:100];
    
    // 方式 3: 渐进式分配(模拟内存泄漏)
    // [[MemoryBomber sharedInstance] explodeGraduallyWithTargetMB:1000 interval:0.5];
}

#pragma mark - 处理内存警告

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    
    NSLog(@"⚠️ 收到内存警告!清理资源...");
    
    // 在这里清理你的缓存、释放资源
    // ...
    
    // 释放测试用的内存
    [[MemoryBomber sharedInstance] releaseAllMemory];
}

@end

#pragma mark - 示例 2: 在 AppDelegate 中处理

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

@implementation AppDelegate

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    NSLog(@"⚠️ AppDelegate 收到内存警告!");
    
    // 清理全局缓存
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
    
    // 释放测试内存
    [[MemoryBomber sharedInstance] releaseAllMemory];
}

@end

#pragma mark - 示例 3: 在 SceneDelegate 中使用 (iOS 13+)

@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

@implementation SceneDelegate

// iOS 13+ 内存警告不会走 AppDelegate,需要在 ViewController 中处理
// 或者使用通知监听

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session 
      options:(UISceneConnectionOptions *)connectionOptions {
    
    // 监听内存警告通知
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleMemoryWarning)
                                                 name:UIApplicationDidReceiveMemoryWarningNotification
                                               object:nil];
}

- (void)handleMemoryWarning {
    NSLog(@"⚠️ SceneDelegate 收到内存警告通知");
    [[MemoryBomber sharedInstance] releaseAllMemory];
}

@end

#pragma mark - 示例 4: 命令行测试 (非 UI 环境)

/*
// 在 main.m 或测试代码中:
#import "MemoryBomber.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        // 分配 500MB 内存
        [[MemoryBomber sharedInstance] explodeWithTargetMB:500 chunkSizeMB:50];
        
        // 保持运行,观察内存状态
        [[NSRunLoop currentRunLoop] run];
        
        return 0;
    }
}
*/