普通对象的初始化后占内存大小:16字节
Map对象初始化后占内存大小:0字节
也就是说 Map map = new HashMap(); 这句代码并没有开辟内存空间
当 map.put() 的时候才开辟内存空间
进一步的,如果Map map = new HashMap(17); 我初始化的时候定义了map的大小,那么等我put的时候,开辟的内存空间是多少?
增加2的一次幂,原本是16,由于初始化的时候尺寸大小是17>16 ,那么所占内存变成 16*2 = 32
Map在JDK 7 的时候使用链表实现的,而在JDK8的时候增加的红黑树的属性变成链表+红黑树的形式,其中涉及几个问题。
JDK8的设计是当链表长度>8(且数组长度大于64)的时候变成红黑树结构,而当调用resize方法时,红黑树的节点数<6的时候又切换成链表,为什么要这么做呢,为什么不设计成>8或者小于8的时候切换呢?
因为这样可以防止黑客的攻击,假设设置的都是8为阈值,那么很容易就能使用map的put 和 remove方法使得map的链表和红黑树之间形成来回的切换,这个过程是需要计算的,所以也就会对服务器造成很大压力。
参考 :https://blog.csdn.net/qq_40728490/article/details/105702394
而由于根据链表的索引查询是比较耗时的一件事情(必须遍历节点),引出了一种新的攻击方式:(JDK7)
map的put操作是根据计算hash值来确定k-v entity在数组的存放位置,如果有hash碰撞那么就将新元素作为存放位置的链表新元素接上,但是如果有人故意制造hash碰撞这个事情,那么就会造成链表非常长,导致查询速度变慢,而tomcat在接收参数的时候也是使用的map,这样就会拖慢服务器的速度。
具体方式为请求参数的时候找到一堆key的hash值相等的参数,用这些参数不停地请求服务器,就会产生这种情况
原文:https://www.cnblogs.com/karbon/p/14718455.html