首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么移除元素后,Python中List的容量会减少到10,而不是8?

在Python中,List是一种动态数组,它的容量会根据需要自动调整。当我们向List中添加元素时,如果容量不足,Python会自动分配更多的内存空间来存储新的元素。这个过程中,Python会根据一定的策略来确定新分配的内存空间的大小。

在Python中,List的内存分配策略遵循了一种叫做"over-allocate"的机制。这意味着当我们向List中添加元素时,Python会预先分配比实际需要更多的内存空间。这样做的目的是为了减少频繁的内存分配操作,提高性能。

具体来说,当我们向一个空的List中添加第一个元素时,Python会分配一个固定大小的内存空间来存储这个元素。这个固定大小通常是4个字节(32位系统)或8个字节(64位系统)。当我们继续向List中添加元素时,Python会根据需要动态地分配更多的内存空间。

当List的容量不足以容纳新的元素时,Python会分配一个更大的内存空间,并将原来的元素复制到新的内存空间中。而在这个过程中,Python会根据一定的策略来确定新分配的内存空间的大小。一般来说,Python会将新分配的内存空间的大小设置为当前容量的两倍。

然而,当我们从List中移除元素时,Python并不会立即释放被移除元素所占用的内存空间。相反,Python会将这些被移除的元素标记为可回收的,并在需要时进行内存回收。这是因为频繁地释放和分配内存空间会带来一定的性能开销。

所以,当我们移除元素后,List的容量不会立即减少,而是保持不变。只有当List中的元素个数减少到一定程度时,Python才会根据一定的策略来减少List的容量。一般来说,当List中的元素个数减少到容量的四分之一左右时,Python会将List的容量减少到当前元素个数的两倍。

总结起来,移除元素后,Python中List的容量会减少到10而不是8,是因为Python采用了一种"over-allocate"的内存分配策略,为了提高性能,在移除元素后并不会立即释放被移除元素所占用的内存空间,而是在需要时进行内存回收,并在元素个数减少到容量的四分之一左右时,才会减少List的容量。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

【Java提高十六】集合List接口详解

它允许任何符合规则的元素插入甚至包括null。每一个ArrayList都有一个初始容量(10),该容量代表了数组的大小。随着容器中的元素不断增加,容器的大小也会随着增加。...每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。默认初始容量为10。随着ArrayList中元素的增加,它的容量也会不断的自动增长。...在前面就提过ArrayList每次新增元素时都会需要进行容量检测判断,若新增元素后元素的个数会超过ArrayList的容量,就会进行扩容操作来满足新增元素的需求。...在这里有一个疑问,为什么每次扩容处理会是1.5倍,而不是2.5、3、4倍呢?通过google查找,发现1.5倍的扩容是最好的倍数。...因为Vector底层是使用数组实现的,所以它的操作都是对数组进行操作,只不过其是可以随着元素的增加而动态的改变容量大小,其实现方法是是使用Arrays.copyOf方法将旧数据拷贝到一个新的大容量数组中

1.1K31

一道算术题:ArrayDeque + ArrayList = LinkedList

的数组容量保证是 2 的整数幂; 3、ArrayDeque 不是线程安全的; 4、ArrayDeque 不支持 null 元素; 5、ArrayDeque 虽然入栈和入队有可能会触发扩容,但从均摊分析上看依然是...因为 ArrayDeque 禁止存储 null 元素,所以需要逐个判断元素是否为 null 值后才添加。 ‍♀️疑问 6:为什么 ArrayDeque 要求数组容量是 2 的整数幂?...搬运数据的过程就是把 head 头指针到数组末尾的元素拷贝到数组头部,而剩下的从数组头部到尾指针的元素则衔接到后面,使得所有元素规整地排列在数组的头部: // 扩容操作 private void doubleCapacity...显然不是这么一回事。第一,数组的容量显示是被虚拟机固化的,不可能无限容量。...总结 1、ArrayDeque 是基于动态数组的线性表,具备 Queue 和 Stack 的行为,但不具备 List 的行为; 2、ArrayDeque 的数组容量是 2 的整数幂,在扩容时容量会翻倍,

50320
  • ArrayList源码解析

    (如数组)支持的该接口所需的工作.对于连续的访问数据(如链表),应优先使用 AbstractSequentialList,而不是此类....查阅资料后,大概知道:transient标识之后是不被序列化的 但是ArrayList实际容器就是这个数组为什么标记为不序列化??那岂不是反序列化时会丢失原来的数据?...原因在于elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,就可以保证只序列化实际存储的那些元素,而不是整个数组...有了上面的步骤后就可以安全的将集合复制到elementData的index,也就完成了集合的插入. 其实我们可以看到,源码中对于细节的处理很细致,值得学习. 五、删除元素 1....=,而不是cursor<=size,这里有点蒙 return cursor !

    50520

    这可能是最细的ArrayList详解了!

    那么为何会产生这种说法呢?原因是**在 jdk 1.2 ~ jdk 1.6 中,ArrayList 的确是会通过空参构造方法生成一个指定底层数据结构容量为 10 的空数组**。...:2 // 扩容后,容器的容量:7 /** * 如若没有指定,默认初始容量为 10 ,扩容后的容量为原容器容量的两倍...i = 0; i 8; i++) { list2.add("填满默认容量"); } System.out.println("扩容后...,容器的容量:" + list2.capacity()); // 输出 // 扩容前,容器的容量:10 // 扩容后,容器的容量:20...**内存空间占用:** `ArrayList` 的空间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 `LinkedList` 的空间花费则体现在它的每一个元素都需要消耗比 `ArrayList

    92100

    ArrayList详解

    那么为何会产生这种说法呢?原因是在 jdk 1.2 ~ jdk 1.6 中,ArrayList 的确是会通过空参构造方法生成一个指定底层数据结构容量为 10 的空数组。...为没有存放任何元素的空集合,那么在执行ensureCapacityInternal()中 calculateCapacity() 方法过后,minCapacity 会变为 10。.../** * 如若没有指定,默认初始容量为 10 ,扩容后的容量为原容器容量的两倍 */ Vector list2 = new Vector();...} System.out.println("扩容后,容器的容量:" + list2.capacity()); // 输出 // 扩容前,容器的容量:10...内存空间占用: ArrayList 的空间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间

    24030

    【深入理解java集合系列】ArrayList实现原理

    在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。 注意,此实现不是同步的。...,也会导致被移除的元素以后的所有元素的向左移动一个位置。...6) 调整数组容量: 从上面介绍的向ArrayList中存储元素的代码中,我们看到,每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,如果超出,数组将会进行扩容,以满足添加数据的需求...,数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。...在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。

    40310

    ArrayList源码解析,老哥,来一起复习一哈?

    /** * 带一个集合参数的构造方法 * * @param c 集合,代表集合中的元素会被放到list中 * @throws 如果集合为空,抛出NullPointerException */...而java.util.Arrays的私有内部类ArrayList的toArray()方法可能不返回Object[]。 为什么会这样?...DEFAULTCAPACITY_EMPTY_ELEMENTDATA,new ArrayList(0)会将elementData 赋值为 EMPTY_ELEMENTDATA,EMPTY_ELEMENTDATA添加元素会扩容到容量为...1,而DEFAULTCAPACITY_EMPTY_ELEMENTDATA扩容之后容量为10。...面对并发修改,迭代器快速失败、清理,而不是在未知的时间不确定的情况下冒险。请注意,快速失败行为不能被保证。通常来讲,不能同步进行的并发修改几乎不可能做任何保证。

    63610

    Java面试题:ArrayList底层实现原理、HashMap的实现原理、HashMap的jdk1.7和jdk1.8有什么区别

    size这个变量有两层含义:①元素的个数,也就是集合的长度;②下一个元素的存入位置添加第一个元素时,底层会创建一个新的长度为10的数组。...添加完毕后,size++存满时,会扩容1.5倍(扩容时机一:当存满时候,会创建一个新的数组,新数组的长度 是原来的1.5倍,也就是长度为15。再把所有的元素,全拷贝到新数组中。...1.3 ArrayList list=new ArrayList(10)中的list扩容几次该语句只是声明和实例了一个ArrayList,指定了容量为10,未扩容。...static final int TREEIFY_THRESHOLD = 8;//当一个反树化的阈值,当这个node长度减少到该值就会从树转化成链表static final int UNTREEIFY_THRESHOLD...扩容逻辑:HashMap 使用的是拉链法来解决散列冲突,扩容并不是必须的,但是不扩容的话会造成拉链的长度越来越长,导致散列表的时间复杂度会倾向于 O(n) 而不是 O(1)。

    20500

    《Java 算法与数据结构》第2章:数组

    二维数组 二维以及多维数组,在开发场景中使用到的到不是不多,不过在一些算法逻辑,数学计算中到是可以使用。...在一些数据存放和使用的场景中,基本也都是使用 ArrayList 而不是 LinkedList,具体性能分析参考:LinkedList插入速度比ArrayList快?你确定吗?...那么在 add 添加元素时统一完成这个事情,还是比较好处理的。 之后就是随着元素的添加,容量是会不足的。当容量不足的是,需要进行扩容操作。同时还得需要把旧数据迁移到新的数组上。...也正因为搜索元素的便捷性,才让 ArrayList 使用的那么广泛。同时为了兼容可以通过元素来获取数据,而不是直接通过下标,引出了 HashMap 使用哈希值计算下标的计算方式,也引出了斐波那契散列。...ArrayList 中顺序添加元素,逐步测试扩容迁移元素,以及删除元素后数据的迁移。

    42710

    java核心数据结构总结

    对基于链表和基于数组的两种List的不同实现做一些比较:   1、增加元素到列表的末尾:   在ArrayList中源代码如下: 1 public boolean add(E e) { 2...由于ArrayList是基于数组实现的,而数组是一块连续的内存,如果在数组的任意位置插入元素,必然会导致该位置之后的所有元素重新排序,其效率相对较低。   ...在ArrayList中,对于remove()方法和add()方法一样,在任意位置移除元素,都需要数组复制。   ...,如果元素位于前半段则,从前往后找;若位置位于后半段,则从后往前找,但是要移除中间的元素,却几乎要遍历半个List。...如:for(int i=0;ilist.size();i++),可以将list.size()分离出来。   2、省略相同的操作   3、减少方法的调用,方法调用时消耗系统堆栈的,会牺牲系统的性能。

    42320

    【久远讲算法3】数组——最简单的数据结构

    (实际上在 python 的 numpy 库中是存在有数组这样一个数据结构的,之后我们会专门写一篇文章来分析数组和列表的异同。)..., 超越指定的长度时,它会进行越界报错,而动态数组的长度是没有准确规定,只要不超出内存,即可在数组末尾一直添加元素,这点是不是和python中的列表很像呢?...比如我定义了一个数组,长度为 6 ,而从 0 到 5 这6个位置,都有元素,数组已经满了,但是我们依旧想要向其中插入插入元素,这个时候我们就需要扩大数组的长度了,可是数组的长度在创建时就已经确定了,不是说变就可以轻易的改变的...删除简单的地方在于,我们无需关心下标是否会越界,容量是肯定不会超过申请的大小的。...'blue' ,打印列表可以发现,我们原列表中的 0 号位的 'red' 和 3 号位的 'blue' 都被删掉了,而剩下的 'red' 和 'blue' 没有被移除。

    81600

    为什么都用哈希? Hash 表认知

    在Java 中当哈希表的元素个数超过容量乘以加载因子(默认为0.75)时,会触发扩容,扩容会重新计算大小,扩容后的大小为。newCap = oldCap 容量的一倍。...Java 中的哈希表就使用链接法解决冲突。在 Java8 之后,链表节点超过8个自动转为红黑树,小于6个会自动转为链表。...上面我们讲到 Java 中 HashMap 会在数组元素个数超过数组容量的 0.75 进行扩容, 扩容机制与上面类似,扩容后的容量始终为 2的幂, 比如如何 HashMap 的初始容量设置为 100,...因此,如果初始容量为 128,扩容后的新容量将是: newCapacity = 128 * 2 = 256(2^8) 所以,初始容量设置为 100,扩容后的容量将为 256。...一致性哈希的优势 最小化数据迁移:当节点加入或离开时,只需重新映射少量数据项,而不是重新分配所有数据。这使得系统在扩展或缩减时更为高效。

    19710

    JDK8中ArrayList的工作原理剖析

    JDK8源码中的ArrayList类结构定义如下: ?...grow(minCapacity),扩容的长度是增加了原来数组数组的一半大小,然后并判断了是否达到了数组扩容的上限并赋值,接着把旧数组的数据拷贝到扩容后的新数组里面再次赋值给旧数组,最后把新添加的元素赋值给了扩容后的...remove方法与add(int index, E element)正好是一个相反的操作过程,移除一个元素,会影响到一批数据的位置移动,所以也是比较耗性能的。 (三)查询 ? (四)修改 ?...总结: 本文介绍了JDK8中的ArrayList的工作原理和常用方法分析,此外ArrayList非线程安全,所以需要多线程的场景下,请使用jdk自带并发List结构或者Guava,Apache Common...基于数组实现的List在随机访问和遍历的效率比较高,但在插入指定和删除指定元素的时候效率比较低,而这正好和链表相反,链表的的查询和随机遍历效率较低,但插入和删除指定位置元素的效率比较高,这也是为什么HashMap

    79650

    Java ArrayList源码分析,带你拿下面试官(含扩容机制等重点问题分析)

    ,会扩容到 DEFAULT_CAPACITY = 10 ) */ transient Object[] elementData; // non-private to simplify nested...add 第 2 到 10 个元素的时候(以 2 举例):此时 minCapacity = size + 1 = 1 + 1 = 2 ,而 elementData.length 已经在添加第 1 个元素后等于...8, 9] 9 替换 6,r++ ,w++ 9 6 自己走一遍上面的逻辑,就能深刻的感受得到 这步的作用:把需要移除的数据都替换掉,不需要移除的数据前移。...当突然 ArrayList 的 remove 方法被调用(不是 Itr 的 remove),会导致被删除元素后面的所有元素都会往前移动一位,且 modCount 这个修改次数会增加,继续循环,去执行 next...} } } //运行结果 I love you ❤ 两者均可以解决并发修改异常的问题,但是通过运行结果也可以看出,方法一添加后,在本次遍历中不会输出添加的结果,而方法二却可以。

    1.7K22

    Java 集合框架(3)---- List 相关类解析(下)

    /** * 记录数组列表中元素的个数 */ private int size; 看到这里可能有些小伙伴们会问了:不是说 ArrayList 类默认的构造方法会构造出一个容量为...10 的数组吗,为什么在 ArrayList 类默认的构造函数中只看到了一句 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; 的代码,并且在后面的代码中也显示出这个...好了,这样的话我们就把 ArrayList 的添加元素的整个流程过了一遍,主要流程也不复杂: 先判断元素数组是否需要扩容 ⇒ 确定扩容后的容量(第一次将容量调整为默认容量(10),之后 以1.5 倍数进行扩容...)⇒ 判断扩容后容量是否溢出 ⇒ 进行数组扩容并复制原数组元素到新数组中。...1 中的 size 的值会变成 oldSize + 1,之后线程 1 将主内存中 size 的值更新为 oldSize + 1(其实线程 2 之前已经将主内存中 size 的值加一了),此时出现了明明添加了两个元素到

    66640

    大厂必问的Java集合面试题

    ArrayList扩容的本质就是计算出新的扩容数组的size后实例化,并将原有数组内容复制到新数组中去。默认情况下,新的容量会是原容量的1.5倍。...的实现中,优化了高位运算的算法,通过hashCode()的高16位异或低16位实现的:这么做可以在数组比较小的时候,也能保证考虑到高低位都参与到Hash的计算中,可以减少冲突,同时不会有太大的开销。...1.8扩容机制:当元素个数大于threshold时,会进行扩容,使用2倍容量的数组代替原有数组。采用尾插入的方式将原数组元素拷贝到新数组。...非阻塞队列中的几种主要方法: add(E e) : 将元素e插入到队列末尾,如果插入成功,则返回true;如果插入失败(即队列已满),则会抛出异常; remove() :移除队首元素,若移除成功,则返回...所谓通知模式,就是当生产者往满的队列里添加元素时会阻塞生产者,当消费者消费了一个队列中的元素后,会通知生产者当前队列可用。

    1.4K31

    彻底搞懂ArrayList

    =Object[].class,那么会重新拷贝一份数据到新的数组中,并且elementData会指向新的数组。...extends E> c构造ArrayList,为什么先调用c.toArray(),然后再判断size大小呢,而不是先调用c.size判断大小后,再调用c.toArray()?...答案:不通过迭代器删除元素时,由于数据会进行前移,可能(不是一定,要考虑元素的位置)会造成数组越界和数据遗漏(i+1的元素前移到i的位置,那么原来i+1的元素就会被遗漏掉),通过迭代器remove删除元素后...至于为什么移除元素必须调用next方法是因为迭代器remove的元素必须要遍历过,如果没有遍历过那么lastRet=-1,迭代器会抛出异常,而且删除后lastRet重新等于-1,所以每次删除都需要调用next...答案:会影响到,在SubList源码中我们可以发现,其内部的操作函数实际上都是对ArrayList的elementData的操作。

    44731
    领券