首页 > 解决方案 > 了解异步 Logger 中的环形缓冲区

问题描述

在 log4j2 手动链接的异步记录器中

log4j2.asyncLoggerConfigRingBufferSize默认值为256 * 1024

256和在这里代表什么1024

标签: javalogginglog4j2

解决方案


环形缓冲区中的插槽数必须是 2 的幂。这允许您不断递增计数器并使用位掩码而不是模数从计数器获取数组索引。

例如,假设我们有一个大小为 4 的环形缓冲区。索引03数组的有效索引。我们想避免检查index++; if (index > 3) { index = 0; }。在一个紧密的循环中,这个if检查会减慢速度。我们能避免吗?

我们可以。我们可以直接递增而不检查,当我们从数组中获取一个值时,我们会忽略所有 4 的倍数(数组的大小)。人们经常为此使用模运算:value = array[index % 4];

3 % 4 = 3
4 % 4 = 0
5 % 4 = 1
...

这很好用,但我们可以做得更好。模运算适用于任何数组大小,但我们选择数组大小为 2 的幂是有原因的:位掩码!位掩码可以实现同样的效果,但速度要快得多(大约快 25 倍)。

这是如何运作的?如果数组是 2 的幂,我们通过减 1 得到它的位掩码。然后我们在从数组中获取值时使用这个掩码:value = array[index & mask];

对于 4,位掩码为 4-1=3。3 的二进制表示是11. 让我们看一下与之前相同的示例:

0011 & 0011 = 0011 (3 & 3 = 3)
1000 & 0011 = 0000 (4 & 3 = 0)
1001 & 0011 = 0001 (5 & 3 = 1)
...

所以这与取模相同,但速度更快。同样,关键点是数组必须是 2 的倍数。

回到问题: ringbuffer 中的实际插槽数是262144. 文档256 * 1024说明这是 2 的幂。


推荐阅读