【问题标题】:Swift Combine - Does the zip operator retain all values that it hasn't had a chance to publish?Swift Combine - zip 运算符是否保留它没有机会发布的所有值?
【发布时间】:2020-12-08 15:55:38
【问题描述】:

这是我想知道的代码:

final class Foo {
    
    var subscriptions = Set<AnyCancellable>()
    
    init () {
        Timer
            .publish(every: 2, on: .main, in: .default)
            .autoconnect()
            .zip(Timer.publish(every: 3, on: .main, in: .default).autoconnect())
            .sink {
                print($0)
            }
            .store(in: &subscriptions)
    }
}

这是它产生的输出:

(2020-12-08 15:45:41 +0000, 2020-12-08 15:45:42 +0000)
(2020-12-08 15:45:43 +0000, 2020-12-08 15:45:45 +0000)
(2020-12-08 15:45:45 +0000, 2020-12-08 15:45:48 +0000)
(2020-12-08 15:45:47 +0000, 2020-12-08 15:45:51 +0000)

这段代码最终会因为内存不足而崩溃吗?似乎 zip 运算符正在存储它收到但尚未发布的每个值。

【问题讨论】:

  • 我会说你的假​​设是正确的 - Zip 将保存越来越多的更快计时器的值。
  • 当然,积累到足以让应用崩溃的程度需要很长时间。每 6 秒它持有一个额外的 Date 对象。不确定 Date 对象有多大,但如果是 8 个字节,那么要达到 100M 大约需要 900 天(如果我计算正确的话)

标签: memory-leaks timer zip combine publisher


【解决方案1】:

zip 确实限制其上游缓冲区大小。你可以这样证明:

import Combine

let ticket = (0 ... .max).publisher
    .zip(Empty<Int, Never>(completeImmediately: false))
    .sink { print($0) }

(0 ... .max) 发布者将尝试同步发布 263 个值(也就是说,在将控制权返回给 Zip 订阅者之前)。运行它并在 Xcode 的 Debug navigator 中观察内存量表。会稳步攀升。您可能想在几秒钟后杀死它,因为它最终会耗尽大量内存并使您的 Mac 在最终崩溃之前难以使用。

如果您在 Instruments 中运行它几秒钟,您会看到所有分配都发生在此调用堆栈中,这表明 Zip 在内部使用普通的旧 Array 来缓冲传入的值。

  66.07 MB      99.8%   174      main
  64.00 MB      96.7%   45        Publisher<>.sink(receiveValue:)
  64.00 MB      96.7%   42         Publisher.subscribe<A>(_:)
  64.00 MB      96.7%   41          Publishers.Zip.receive<A>(subscriber:)
  64.00 MB      96.7%   12           Publisher.subscribe<A>(_:)
  64.00 MB      96.7%   2             Empty.receive<A>(subscriber:)
  64.00 MB      96.7%   2              AbstractZip.Side.receive(subscription:)
  64.00 MB      96.7%   2               AbstractZip.receive(subscription:index:)
  64.00 MB      96.7%   2                AbstractZip.resolvePendingDemandAndUnlock()
  64.00 MB      96.7%   2                 protocol witness for Subscription.request(_:) in conformance Publishers.Sequence<A, B>.Inner<A1, B1, C1>
  64.00 MB      96.7%   2                  Publishers.Sequence.Inner.request(_:)
  64.00 MB      96.7%   1                   AbstractZip.Side.receive(_:)
  64.00 MB      96.7%   1                    AbstractZip.receive(_:index:)
  64.00 MB      96.7%   1                     specialized Array._copyToNewBuffer(oldCount:)
  64.00 MB      96.7%   1                      specialized _ArrayBufferProtocol._forceCreateUniqueMutableBufferImpl(countForBuffer:minNewCapacity:requiredCapacity:)
  64.00 MB      96.7%   1                       swift_allocObject
  64.00 MB      96.7%   1                        swift_slowAlloc
  64.00 MB      96.7%   1                         malloc
  64.00 MB      96.7%   1                          malloc_zone_malloc

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 2023-03-05
    • 2016-09-28
    • 1970-01-01
    • 2021-04-30
    • 1970-01-01
    • 2014-07-27
    相关资源
    最近更新 更多