使用`Publishers.Sequence`时发生内存泄漏

问题描述

我具有创建发布者集合的功能:

func publishers(from text: String) -> [AnyPublisher<SignalToken,Never>] {
     let signalTokens: [SignalToken] = translate(from: text)
     var delay: Int = 0
     let signalPublishers: [AnyPublisher<SignalToken,Never>] = signalTokens.map { token in
         let publisher = Just(token)
                           .delay(for: .milliseconds(delay),scheduler: DispatchQueue.main)
                           .eraseToAnyPublisher()
         delay += token.delay
         return publisher
     }
     return signalPublishers
}

在服务类中,我必须使用方法,其中一个用于play()

func play(signal: String) {
     anyCancellable = signalTokenSubject.sink(receiveValue: { token in print(token) }

     anyCancellable2 = publishers(from: signal)
         .publisher
         .flatMap { $0 }
         .subscribe(on: DispatchQueue.global())
         .sink(receiveValue: { [weak self] token in
            self?.signalTokenSubject.send(token)
         })
}

和一个stop()

func stop() {
     anyCancellable?.cancel()
     anyCancellable2?.cancel()
}

我的记忆有问题。如果发布者的数量很大,并且在整个stop()之前我Publishers.Sequence.finshed,则内存增加并且永远不会释放。

在合并对整个集合进行迭代之前,是否有办法提前completed Publishers.Sequence

解决方法

要回收内存,请释放管道:

func stop() {
     anyCancellable?.cancel()
     anyCancellable2?.cancel()
     anyCancellable = nil 
     anyCancellable2 = nil 
}

实际上,您不需要进行cancel调用,因为释放管道确实可以按顺序取消;这就是AnyCancellable的重点。所以你可以说:

func stop() {
     anyCancellable = nil 
     anyCancellable2 = nil 
}

要注意的另一件事是您正在同时运行所有发布者。序列没有顺序到达; 整个序列被转储到flapMap中,这将启动所有发布者同时发布。因此取消并不能为您带来很多好处。您可能希望在maxPublishers:上设置flatMap,以使背压可以防止同时到达多个发布者(例如一次一个)。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...