2021-04-25

1 篇文章 0 订阅

项目中遇到的内存泄露

现象:

RN页调用客户端的选择相册图片功能,然后RN页通过广播来接收结果,关闭这个RN页之后发现,广播还在接收。

排查:

1、检查这个广播广播listener有没有移除,发现RN的componentWillUnmount()里有调用listener.remove();

2、添加log发现返回上一页之后,没有走到componentWillUnmount(),判定是页面没有被释放。

3、iOS Debug,发现ReactController(iOS中的RN页容器),在返回上一页时,没有调用dealloc方法,这种情况通常是内存泄露引起的

4、使用Xcode的Instruments检测解决iOS内存泄露(Leak)发现该页确实有内存泄露。

5、定位到iOS中有一个Block的循环引用。

原代码:

- (void)showImagePicker:(UIImagePickerControllerSourceType)sourceType edit:(BOOL)edit
{
    switch (sourceType) {
        case UIImagePickerControllerSourceTypeCamera:
        {
            [SystemAuthHelper checkIsAuthorized:SystemAuthTypeCamera result:^(BOOL result) {
                if (result) [self doShowImagePicker:sourceType edit:edit];
            } forWriteOnly:NO];
        }
            break;
        case UIImagePickerControllerSourceTypePhotoLibrary:
        case UIImagePickerControllerSourceTypeSavedPhotosAlbum:
        {
            [SystemAuthHelper checkIsAuthorized:SystemAuthTypeAlbum result:^(BOOL result) {
                if (result) [self doShowImagePicker:sourceType edit:edit];
            } forWriteOnly:NO];
        }
            break;
        default:
            break;
    }
}

可以看到Block内用的self,导致了循环引用

修复后

- (void)showImagePicker:(UIImagePickerControllerSourceType)sourceType edit:(BOOL)edit
{
    __weak typeof(self) weakSelf = self;
    switch (sourceType) {
        case UIImagePickerControllerSourceTypeCamera:
        {
            [SystemAuthHelper checkIsAuthorized:SystemAuthTypeCamera result:^(BOOL result) {
                if (result) [weakSelf doShowImagePicker:sourceType edit:edit];
            } forWriteOnly:NO];
        }
            break;
        case UIImagePickerControllerSourceTypePhotoLibrary:
        case UIImagePickerControllerSourceTypeSavedPhotosAlbum:
        {
            [SystemAuthHelper checkIsAuthorized:SystemAuthTypeAlbum result:^(BOOL result) {
                __typeof(self) weakSelf2 = weakSelf;
                if (!weakSelf2) {
                    return;
                }                                
                if (result) [weakSelf2 doShowImagePicker:sourceType edit:edit];
            } forWriteOnly:NO];
        }
            break;
        default:
            break;
    }
}

反思

RN开发遇到监听有调用remove()但是没有移除,或者说页面没有销毁,大概率是内存泄露导致的。

本次是因为客户端内存泄露导致的,但是平时开发RN也要注意内存泄露,因此总结一下。

iOS内存泄露

内存泄露会导致dealloc无法调用,内存泄露根本原因是循环引用

内存泄露三大原因:

一、NSTimer没有销毁

[
    NSTimer 
    scheduledTimerWithTimeInterval:self.autoDismissDuration 
    target:self 
    selector:@selector(dismiss) 
    userInfo:nil 
    repeats:NO
 ];

注意:别忘了调用[timer invalidate]

二、ViewController中的代理delegate

@protocol ClassADelegate <NSObject>
@optional
- (void)didChange;
@end

@interface ClassA : NSObject

@property (nonatomic, weak) id<ClassADelegate> delegate;

@end

注意:delegate要用weak修饰,不能用strong

三、Block循环引用

见上面的问题修复的例子

RN内存泄露

一、文件循环引用

View1:
import { View2 } from './View2';

export const  ConstValueA = 'aaaaaaaa';
export const View1 = (props) => {
    return <View2/>;
};


View2: 
import { ConstValueA } from './View1';
export const View2 = (props) => {
    return <Text>{ConstValueA}</Text>
};
    

View1和View2循环引用

修改:

View1:
import { View2 } from './View2';

export const View1 = (props) => {
    return <View2/>;
};


utils:
export const  ConstValueA = 'aaaaaaaa';


View2: 
import { ConstValueA } from './utils';
export const View2 = (props) => {
    return <Text>{ConstValueA}</Text>
};
    

二、广播没有及时清理

 componentDidMount() {
      this.listener = NativeEmitter.addListener(
        'info_change',
        event => {
         
        }
      );
    }

//注意移除
 componentWillUnmount() {
    if (this.listener) {
       this.listener.remove();
    }
 }   

Hooks的写法

    useEffect(() => {
        let listener = MaiMaiNativeEmitter.addListener(
            'action.to.webview',
            handleBoradcast
          );

          //注意这里要remove
          return () => {
            listener.remove();
          };
  }, []);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用python中的pymsql完成如下:表结构与数据创建 1. 建立 `users` 表和 `orders` 表。 `users` 表有用户ID、用户名、年龄字段,(id,name,age) `orders` 表有订单ID、订单日期、订单金额,用户id字段。(id,order_date,amount,user_id) 2 两表的id作为主键,`orders` 表用户id为users的外键 3 插入数据 `users` (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28); `orders` (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4); 查询语句 1. 查询订单总金额 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 3. 查询订单总数最多的用户的姓名和订单总数。 4. 查询所有不重复的年龄。 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 8. 查询订单总金额最大的用户的姓名和订单总金额。 9. 查询订单总金额最小的用户的姓名和订单总金额。 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。
最新发布
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值