引言
在看redis源码的过程中,看到了redis为了高效使用内存,内部维护了个Integer常量池,使得redis对于频繁出现的Integer,能够减少内存的使用,也减少了内存申请和释放的开销,所以把各种场景的常量池做次归纳。
各种常量池
Java常量池
JVM字符串常量池
这个太多常见了,直接google即可
Integer常量池
对于Intger常量池,可以看下面这个例子,a和b变量都是引用类型,但进行“==”判断是否是同个引用的时候返回有时会返回true,这个是什么原因呢?因为JVM内部自己维护了个常量池,a和b都是指向了相同的“常量”实例,所以”==”会返回true, 而cd的值超出了默认常量值的范围,所以“==”返回false.
1 | public static void main(String[] args) throws Exception { |
那在jdk里面是如何使用到这个常量池的?
源码,从Integer.valueOf()方法中可以看出这里是使用了cache,也就是Integer常量值,对于 Integer a = 1这种statement, jvm其实也就是调用了valueOf方法进行boxing. IntegerCache.high是可以通过设置jvm参数进行改变。
1 | public static Integer valueOf(int i) { |
所以以下这种坏味道的代码,也不会造成明显的性能影响
1 | for (Integer i = 0; i < 10; i++){ |
Redis 常量池
通常会遇到redis的一种使用场景,只是想通过设置某个key,然后通过判断某个key是否存在,value的值没任何意义,这个时候就会纠结value应该取什么值比较省内存,如果通过redis-rdb-tools进行内存计算,可以得出以下结果,空字符串的value内存占用比保存’1’占用了多8个字节的长度,这是因为对于’’需要保存一个空字符串,而对于’1’,则命中了redis整形常量池,无需而外分配内存保存’1’,整个数据存储的占用等另开一篇文章说明。
1 | set k '' #总共占用56字节 |
Redis在编码字符串是会尝试进行一些压缩编码,以下代码就是redis使用整形常量池的片段
常量池初始化
1 | for (j = 0; j < OBJ_SHARED_INTEGERS; j++) { |
常量池使用
1 | if (len <= 20 && string2l(s,len,&value)) { |