我浏览了Blink代码库以回答有关JavaScript中可能的最大计时器数量的question。
新计时器由DOMTimerCoordinator::InstallNewTimeout()
创建。它调用NextID()
来检索可用的整数键。然后,它将新的计时器和相应的键插入timers_
中。
int timeout_id = NextID();
timers_.insert(timeout_id, DOMTimer::Create(context, action, timeout,
single_shot, timeout_id));
NextID()
以1到2的循环顺序获取下一个id 31 -1:
int DOMTimerCoordinator::NextID() {
while (true) {
++circular_sequential_id_;
if (circular_sequential_id_ <= 0)
circular_sequential_id_ = 1;
if (!timers_.Contains(circular_sequential_id_))
return circular_sequential_id_;
}
}
如果所有ID都在使用,该怎么办?
是什么阻止NextID()
进入无限循环?
在我的answer中对该问题进行了更详细的说明。
答案 0 :(得分:2)
我需要一点时间来理解这一点,但我相信我明白了。
这些步骤对我来说很有意义。
circular_sequential_id_
用作唯一标识符。它没有公开,但从其他信息来看,我怀疑它是一个32位的int
(例如std::int32_t
)。
我怀疑circular_sequential_id_
是class
(或struct
)DOMTimerCoordinator
的成员变量。因此,在每次调用NextID()
之后,它“记住”最后返回的值。输入NextID()
后,circular_sequential_id_
首先递增:
++circular_sequential_id_;
++circular_sequential_id_;
的增量可能迟早会引起溢出(嗯。如果我没记错的话,这被认为是Undefined Behavior,但在现实世界中,它几乎只是绕来绕去。)并变为负数。为了解决这个问题,下一行适用于:
if (circular_sequential_id_ <= 0)
circular_sequential_id_ = 1;
循环中的最后一条语句检查在任何计时器中是否仍在使用生成的ID:
if (!timers_.Contains(circular_sequential_id_))
return circular_sequential_id_;
如果未使用,则返回ID。否则,“ Sam,再玩一次。”
这给我带来了最合理的答案:
是的,这可能会变成无休止的循环...
...如果2 31 -1个定时器已被占用,则所有ID均已消耗。
我假设使用2 31 -1个计时器,您还有其他更重要的问题。 (单独想象一下那些计时器可能需要的存储空间以及处理所有计时器的时间...)
即使2个 31 -1个计时器不是致命的问题,该功能也可能会进一步循环,直到其中一个计时器释放其ID并可以再次使用它。因此,如果资源(计时器的免费ID)暂时不可用,NextID()
将被阻止。
三思而后行,2.选项在理论上是相当合理的。我不敢相信有人会以此方式管理有限的资源。
我猜想,这段代码是在假设不会同时存在2 31 -1个计时器的情况下工作的,因此它将发现带有几次迭代的空闲ID。