内存池采用了slab分配思路,内存被划分成多种不同大小的内存单元,在分配内存时根据使用者请求的内存大小进行计算,匹配最接近的内存单元。在计算时分下面几种情况:
请求的内存大小是否超过了chunkSize,如果已超出说明一个该内存已经超出了一个chunk能分配的范围,这种内存内存池无法分配应由JVM分配,直接返回原始大小。
请求大小大于等于512,返回一个512的2次幂倍数当做最终的内存大小,当原始大小是512时,返回512,当原始大小在(512,1024]区间,返回1024,当在(1024,2048]区间,返回2048等等。
请求大小小于512,返回一个16的整数倍,原始大小(0,16]区间返回16,(16,32]区间返回32,(32,48]区间返回48等等,这些大小的内存块在内存池中叫tiny块。
相关代码在PoolArena的normalizeCapacity方法:
int normalizeCapacity(int reqCapacity) {if (reqCapacity < 0) {throw new IllegalArgumentException("capacity: " + reqCapacity + " (expected: 0+)");}if (reqCapacity >= chunkSize) {return directMemoryCacheAlignment == 0 ? reqCapacity : alignCapacity(reqCapacity);}if (!isTiny(reqCapacity)) { // >= 512// Doubledint normalizedCapacity = reqCapacity;normalizedCapacity --;normalizedCapacity |= normalizedCapacity >>> 1;normalizedCapacity |= normalizedCapacity >>> 2;normalizedCapacity |= normalizedCapacity >>> 4;normalizedCapacity |= normalizedCapacity >>> 8;normalizedCapacity |= normalizedCapacity >>> 16;normalizedCapacity ++;if (normalizedCapacity < 0) {normalizedCapacity >>>= 1;}assert directMemoryCacheAlignment == 0 || (normalizedCapacity & directMemoryCacheAlignmentMask) == 0;return normalizedCapacity;}if (directMemoryCacheAlignment > 0) {return alignCapacity(reqCapacity);}// Quantum-spacedif ((reqCapacity & 15) == 0) {return reqCapacity;}return (reqCapacity & ~15) + 16;}
分配的内存大小小于512时内存池分配tiny块,大小在[512,pageSize]区间时分配small块,tiny块和small块基于page分配,分配的大小在(pageSize,chunkSize]区间时分配normal块,normall块基于chunk分配,内存大小超过chunk,内存池无法分配这种大内存,直接由JVM堆分配,内存池也不会缓存这种内存。
关于Doubled算法:
int normalizedCapacity = reqCapacity;normalizedCapacity |= normalizedCapacity >>> 1;normalizedCapacity |= normalizedCapacity >>> 2;normalizedCapacity |= normalizedCapacity >>> 4;normalizedCapacity |= normalizedCapacity >>> 8;normalizedCapacity |= normalizedCapacity >>> 16;normalizedCapacity ++;
以128 双倍为例:
10000000
|
01000000
=
11000000
11000000
|
00110000
=
11110000
11110000
|
00001111
=
11111111
11111111
|
00000000
=
11111111
11111111
|
00000000
=
11111111
最后结果:256
解析:
对于不超过2的16方的数,最高数字位是1,右移一位,做或运算,可以保证最高两位数字位全是1;再右移两位,做或运算后,最高四位数字位全是1;依次类推,最高位是1的个数倍增。
据此,255 运算后,因为全部数字位都是1,所以运算后,还是255。