Description
I found some PoolArena allocations value was incorrect, more specifically is:
long numTinyAllocations();
long numSmallAllocations();
long numNormalAllocations();
and
long numNormalDeallocations();
When I alloc Pooled ByteBuf & and release all these Bufs,
Expected behavior
PoolArena's Metric SHOULD meet the following conditions:
numTinyAllocations() == numTinyDeallocations()
&& numSmallAllocations() == numSmallDeallocations()
&& numNormalAllocations() == numNormalDeallocations()
Actual behavior
BUT now result:
numTinyAllocations() < numTinyDeallocations()
&& numSmallAllocations() < numSmallDeallocations()
&& numNormalAllocations() > numNormalDeallocations()
It seems some tiny & small allocations increase normal's counter, I export PoolArenaMetric as MBean by code and show MBean by Web using zkoss, see below:
In this case,
numAllocations(2404) == numDeallocations(2404)
BUT
(numTinyDeallocations - numTinyAllocations) // == 17
+ (numSmallDeallocations - numSmallAllocations) // == 9
equals
(numNormalAllocations - numNormalDeallocations) // == 26
Steps to reproduce
I start test code with VM flag (disable thread local cache):
-XX:MaxDirectMemorySize=96M
-Dio.netty.allocator.tinyCacheSize=0
-Dio.netty.allocator.smallCacheSize=0
-Dio.netty.allocator.normalCacheSize=0
-Dio.netty.allocator.type=pooled
then alloc some ByteBuf and release Bufs.
Minimal yet complete reproducer code (or URL to code)
TestCase to reproduce: https://github.com/isdom/jocean-http/blob/6bc6cfa9ae1e71395a4dd52355b1b0a8365bb530/jocean-http/src/test/java/org/jocean/netty/buffer/PooledByteBufAllocatorTestCase.java
and make sure run this test with VM flag: -XX:MaxDirectMemorySize=96M
It fail at:
assertEquals(metric.numTinyDeallocations(), metric.numTinyAllocations());
assertEquals(metric.numSmallDeallocations(), metric.numSmallAllocations());
assertEquals(metric.numNormalDeallocations(), metric.numNormalAllocations());
output :
java.lang.AssertionError: expected:<1> but was:<0>
at org.junit.Assert.fail(Assert.java:88)
If this is confirmed as a issue,I can open a PR to fix it.
Netty version
netty-all-4.1.7.Final
JVM version (e.g. java -version
)
java version "1.8.0_102"
Java(TM) SE Runtime Environment (build 1.8.0_102-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.102-b14, mixed mode)
OS version (e.g. uname -a
)
Linux xxx 3.10.0-327.22.2.el7.x86_64 #1 SMP Thu Jun 23 17:05:11 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
Activity
normanmaurer commentedon Jan 26, 2017
@isdom this is because of the caches... when you deallocate the buffers they will first end up in ThreadLocal caches. Only after these removed from the caches they are really deallocated. You can disable the caches to see it.
isdom commentedon Jan 27, 2017
@normanmaurer but I have already disable ThreadLocal caches by set JVM flag:
and Take a look at the following test code:
I think PoolArena try to allocate tiny or small buffer, when PoolSubpage is empty( head.next == head ), tiny or small buffer initialized via function allocateNormal(buf, reqCapacity, normCapacity) , but allocateNormal always increase normal's counter at code1 and code2, these two increment action could be replaced by following code:
Please check PoolArena's allocation increment code (tiny / small / normal ) again, thanks @normanmaurer
normanmaurer commentedon Jan 27, 2017
@isdom doh! You are right. Want to do a PR or should I take care ?
isdom commentedon Jan 27, 2017
@normanmaurer OK,Let me try...
normanmaurer commentedon Jan 27, 2017
@isdom ok cool... Would be nice if just would calculate if its tiny/small/normal allocation one time though and not need to do multiple times 👍
fix netty#6282: calculate correct count for tiny/small/normal allocation
fix netty#6282: acquire the synchronized(this) once when we increment…
fix netty#6282: erase trailing whitespace
fix netty#6282: erase trailing whitespace
Calculate correct count for tiny/small/normal allocation
normanmaurer commentedon Jan 30, 2017
Fixed by #6288
Calculate correct count for tiny/small/normal allocation
Calculate correct count for tiny/small/normal allocation