谈谈 HashMap(int initialCapacity)与内存分配机制
前言
阅读前请先看看如下几个问题,如果有不清楚的地方看完本文会有收获
关于扩容相关原理与一些巧妙的二进制算法分析参考HashMap巧妙的扩容算法
HashMap(int initialCapacity)
在JDK的HashMap中存在无参构造函数和有参构造函数,有参构造函数中又存在带有指定容量和加载因子的构造方法和只带有指定容量的构造方法,本文主要分析下 HashMap(int initialCapacity) 构造方法
public HashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);
}public HashMap(int initialCapacity, float loadFactor) {if (initialCapacity < 0)throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);if (initialCapacity > MAXIMUM_CAPACITY)initialCapacity = MAXIMUM_CAPACITY;if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal load factor: " + loadFactor);this.loadFactor = loadFactor;this.threshold = tableSizeFor(initialCapacity);
}
该方法逻辑比较简单首先校验下容量有没有超多最大值,没有的话设置下加载因子和扩容阈值
算法分析
生成扩容阈值的算法如下,该算法的非常巧妙的用位运算生成大于等于指定容量的最小的2的幂次值例如如果给定一个数为14那么算出大于14的2的最小指数幂等于16
static final int tableSizeFor(int cap) {int n = cap - 1;n |= n >>> 1;n |= n >>> 2;n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}
在十进制数中2的整数次幂对应的二进制数有效位为1且有效位后所有位为0,如下图所示
- 首先解释下为什么先做cap-1操作?当cap已经为2的整数次幂时通过该方法计算会将原来的cap变为2*cap,其实就是为了处理特殊的数据
- 在解释下为什么每次无符号移位操作是1,2,4,8,16?在java中int类型为32位,1+2+4+8+16正好是移动32位,移动32位后的得到的结果是将最高有效位及以后所有位变0位1
假设cap=14,cap-1 =13 其二进制位1101经过下图的变化后发现在第一次位运算后所有有效位都为1111,因此在剩下的四次位运算后最终结果就是1111,最后将1111+1=10000得到十进制数位16。
此时虽然设置了hashmap的threshold但是并没有真正设置hashmap的容量大小,真正容量大小是在向hashmap中插入第一个元素时进行设置
HashMap 内存分配时机
经过构造函数new的Hashmap对象并未真正分配内存空间,这其实是一种优化因为在构造方法就分配内存空间后很久才进行插入操作那么这部分内存其实是浪费的。因此在put操作时会进行判断如果第一次插入则通过resize方法进行进行分配空间。第一次插入时分配的空间大小即为tablesizefor方法返回大小
这种分配方式满足程序局部性原理,在写代码时可以借鉴
- put防范插入数据前判断当前hashMap中table是否初始化
- 未初始化进行resize操作,其实hashmap的初始内存分配跟扩容都是通过resize方法来完成
- resize方法内部通过各种参数判断来执行初始化逻辑跟扩容逻辑
内存分配逻辑-resize
本文只截取部分resize方法分析,剩余扩容逻辑会在新文章中进行讲解。
- 首先判断table 是否为空,因为初始化阶段table=null所以oldCap=0
- 由于在hashmap中带参数的构造方法通过tableSizeFor方法设置了threshold因此table数据的容量为oldThr
- 如果使用无参数构造方法newCap&newThr均使用默认值
- 最后创建数据并指向table
总结
HashMap使用非常巧妙且高效的算法获取了大于等于给定容量的最小2的整数幂,所以在根据hashcode计算元素所属hash表的位置时通过hashcode与(hash表长度-1)进行取模快速定位。
在首次插入进行内存分配机制极大的避免了内存浪费而且满足了局部性原理同样值得学习
谈谈 HashMap(int initialCapacity)与内存分配机制相关推荐
- MySQL • 源码分析 • 内存分配机制
摘要: 前言 内存资源由操作系统管理,分配与回收操作可能会执行系统调用(以 malloc 算法为例,较大的内存空间分配接口是 mmap, 而较小的空间 free 之后并不归还给操作系统 ),频繁的系统 ...
- JAVA入门级教学之(方法内存分配机制)
目录 JAVA入门级教学之(方法内存分配机制) 1.方法只定义,不调用,是不会执行的 2.在JVM内存划分上有这样三块主要的内存空间:[还有其它的内存空间] 3.关于"栈"数据结构 ...
- STL中Vector的内存分配机制
一些好的公司校园招聘过程中(包括笔试.面试环节),经常会涉及到STL中vector的使用(主要是笔试)及其性能(面试)的分析.今天看了下相关文章,也写了几个小的测试程序跑了跑.算是总结下,希望对需要的 ...
- 32g内存 java开发,阿里面试官:小伙子,你给我说一下JVM对象创建与内存分配机制吧...
内存分配机制 逐步分析 类加载检查: 虚拟机遇到一条new指令(new关键字.对象的克隆.对象的序列化等)时,会先去检查这个指令的参数在常量池中定位到一个类的符号引用,并且这个符号引用代表的类是否应被 ...
- Java 虚拟机内存分配机制
Java 虚拟机内存分配机制 内存区域划分 对于大多数的程序员来说,Java 内存比较流行的说法便是堆和栈,这其实是非常粗略的一种划分,这种划分的"堆"对应内存模型的 Java 堆 ...
- linux内存分配机制,Linux内存分配机制:SLAB / SLUB / SLOB
Linux内存分配机制:SLAB / SLUB / SLOB [日期:2011-07-15] 来源:Linux社区 作者:do2jiang [字体:大 中 小] slob: introduce the ...
- JVM——对象创建与内存分配机制
文章目录 1.对象的创建 1.1.类加载检查 1.2.分配内存 1.3.初始化 1.4.设置对象头 1.5.执行方法 2.对象内存分配 2.1. 对象栈上分配 2.2.对象在Eden区分配 2.3.大 ...
- JVM内存分配机制详解
目录 1. 对象创建流程(TODO) 1.1 jvm分配内存 1.2 设置对象头 1.2.1 对象头实例 1.2.2 指针压缩 2.JVM对象内存分配 2.1 逃逸分析和标量替换 2.1.1 逃逸分析 ...
- Linux内存分配机制之伙伴系统和SLAB
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6539590.html 内核内存管理的一项重要工作就是如何在频繁申请释放内存的情况下,避免碎片的产生.这就要求 ...
最新文章
- delphi XE 學習筆記二:TThread.CreateAnonymousThread
- 实战_02_Spring SpringMVC 整合Mybaits
- the development of c language(转)
- 外包公司到底值不值去?
- Unix/Linux 中的 shell 机制
- vb中WindowsMediaPlayer的常用属性和方法
- PHP和MySQL Web开发从新手到高手,第9天-总结
- 一个具有对象计数功能的基类
- 【Android游戏开发二十一】Android os设备谎言分辨率的解决方案!
- 为你的简书和 GitHub 设定个性域名
- javafx 时间输入框
- mousetrap.js使用详解
- 计算机专业毕业设计流程,计算机专业毕业设计答辩流程
- 第14章 Python网络爬虫
- 擦地机器人排行榜_拖地扫地机器人十大品牌排行榜哪个牌子好
- 字符串大小写转换(C/C++实现)
- MU-MIMO和SU-MIMO分别表示什么?
- FL Studio春节大特惠,一起嗨翻狗年
- 下载ug时java更新未完成_UG导入导出Dwg,Dxf文件提示:转换未完成,网上说的方法都试了一遍没用怎么办?...
- SYSU-区块链原理与技术