当前位置:首页 > 科技  > 软件

终于明白为啥面试老是有人问 SubList 了,原来这玩意会 OOM!

来源: 责编: 时间:2024-03-18 09:33:25 280观看
导读最近刚做到一个内存分页的需求,自测了几次就 OOM 了,找了半天原因,终于把这个坑填上来,下面整理一下发出来,各位小伙伴引以为鉴。我们经常会使用 List.subList 方法对 List 进行切片,比如取前十个元素出来用,但是和 Arrays.a

最近刚做到一个内存分页的需求,自测了几次就 OOM 了,找了半天原因,终于把这个坑填上来,下面整理一下发出来,各位小伙伴引以为鉴。xdE28资讯网——每日最新资讯28at.com

我们经常会使用 List.subList 方法对 List 进行切片,比如取前十个元素出来用,但是和 Arrays.asList 的问题类似(具体文章可以看 慎用 ArrayList,全是坑!),List.subList 返回的子 List 不是一个全新地址的 ArrayList,这个子 List 会和原始 List 相互影响。xdE28资讯网——每日最新资讯28at.com

如果不注意,很可能会因此产生 OOM 问题。xdE28资讯网——每日最新资讯28at.com

话不多说,先复现问题。如下代码所示,定义一个名为 data 的静态 List 用来存放 List<Integer> 类型,循环 1000 次,每次都从一个具有 100 万个 Integer 的 List 中(即代码中的 rawList),使用 subList 方法获得一个只包含一个数字的子 List,并把这个子 List 加入 data 变量:xdE28资讯网——每日最新资讯28at.com

图片图片xdE28资讯网——每日最新资讯28at.com

看起来,这个 data 变量里面最终保存的只是 1000 个具有 1 个元素的 List 而已,并不会出现什么问题啊。xdE28资讯网——每日最新资讯28at.com

但是,代码在运行到一段时间后,可以看到在我的机器上是第 159 次循环后发生了 OOM:xdE28资讯网——每日最新资讯28at.com

图片图片xdE28资讯网——每日最新资讯28at.com

出现 OOM 的原因是,循环中的 1000 个具有 100 万个元素的 List 始终得不到回收,因为它始终被 subList 方法返回的 List 强引用。xdE28资讯网——每日最新资讯28at.com

subList 返回的子 List 为啥会强引用原始的 List?再来做个实验看下:xdE28资讯网——每日最新资讯28at.com

首先初始化一个包含数字 1 到 10 的 ArrayList,然后通过调用 subList 方法取出 2、3、4,随后删除这个 SubList 中的元素数字 3。可以看到原始 List 中数字 3 被删除了,说明删除子 List 中的元素影响到了原始 List:xdE28资讯网——每日最新资讯28at.com

图片图片xdE28资讯网——每日最新资讯28at.com

图片图片xdE28资讯网——每日最新资讯28at.com

继续看,我们为原始的 ArrayList 增加一个元素数字 0,然后遍历 SubList 输出所有元素。代码运行后报错 java.util.ConcurrentModificationException:xdE28资讯网——每日最新资讯28at.com

图片图片xdE28资讯网——每日最新资讯28at.com

图片图片xdE28资讯网——每日最新资讯28at.com

分析下 ArrayList 的源码,看看为什么会是这样:xdE28资讯网——每日最新资讯28at.com

图片图片xdE28资讯网——每日最新资讯28at.com

  1. ArrayList 维护了一个 int 类型的 modCount 的字段,表示 List 结构性修改的次数。所谓结构性修改,指的是影响 List 大小的修改,所以 add 操作必然会改变 modCount 的值。
  2. 分析 subList 方法可以看到,获得的 List 其实是创建了一个内部类 SubList,并不是普通的 ArrayList。
  3. 在初始化内部类 SubList 的时候传入了 this,这个 SubList 中的 parent 字段就是原始的 List,初始化的时候,并没有把原始 List 中的元素复制到独立的变量中保存,所以双方对元素的修改都会互相影响。而且 SubList 强引用了原始的 List,所以大量保存这样的 SubList 其实也保存了大量原始的 List,从而导致 OOM。
  4. 分析 listIterator 方法可知,遍历 SubList 的时候会先获得迭代器,比较原始 ArrayList modCount 的值和 SubList 当前 modCount 的值,如果不想等,就会抛出 ConcurrentModificationException 异常。所以上述实验代码,我们在获得了 SubList 为原始 List 新增了一个元素,修改了原始 List 的 modCount,所以判等失败抛出异常。

综上,既然 SubList 和原始 List 会相互影响,那么避免相互影响的修复方式有两种:xdE28资讯网——每日最新资讯28at.com

  1. 不直接使用 subList 方法返回的 SubList,而是重新使用 new ArrayList,在构造方法传入 SubList,来构建一个独立的 ArrayList:
List<Integer> subList = new ArrayList<>(list.subList(1, 4));
  1. 对于 Java 8 使用 Stream 的 skip 和 limit API 来跳过流中的元素,以及限制流中元素的个数,同样可以达到 SubList 切片的目的:
List<Integer> subList = list.stream().skip(1).limit(3).collect(Collectors.toList());

xdE28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-76481-0.html终于明白为啥面试老是有人问 SubList 了,原来这玩意会 OOM!

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 用 React/Vue 不如用 JQuery,你知道吗?

下一篇: SpringCloud微服务中如何实现多端认证?

标签:
  • 热门焦点
  • Find N3入网:最高支持16+1TB

    OPPO将于近期登场的Find N3折叠屏目前已经正式入网,型号为PHN110。本次Find N3在外观方面相比前两代有很大的变化,不再是小号的横向折叠屏,而是跟别的厂商一样采用了较为常见的
  • 每天一道面试题-CPU伪共享

    前言:了不起:又到了每天一到面试题的时候了!学弟,最近学习的怎么样啊 了不起学弟:最近学习的还不错,每天都在学习,每天都在进步! 了不起:那你最近学习的什么呢? 了不起学弟:最近在学习C
  • 2天涨粉255万,又一赛道在抖音爆火

    来源:运营研究社作者 | 张知白编辑 | 杨佩汶设计 | 晏谈梦洁这个暑期,旅游赛道彻底火了:有的「地方」火了&mdash;&mdash;贵州村超旅游收入 1 个月超过 12 亿;有的「博主」火了&m
  • 东方甄选单飞:有些鸟注定是关不住的

    文/彭宽鸿编辑/罗卿东方甄选创始人俞敏洪带队的&ldquo;7天甘肃行&rdquo;直播活动已在近日顺利收官。成立后一年多时间里,东方甄选要脱离抖音自立门户的传闻不绝于耳,&ldquo;7
  • 阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的&ldquo;征求意见版&rdquo;:1、取消P序列
  • 华为Mate 60保护壳曝光:硕大后置相机模组 凸起程度有惊喜

    这段时间以来,关于华为新旗舰的爆料日渐密集。据此前多方爆料,今年华为将开始恢复一年双旗舰战略,除上半年推出的P60系列外,往年下半年的Mate系列也将
  • 机构称Q2国内智能手机销量同比下滑4% vivo份额重回第1

    7月29日消息,根据市场调查机构Counterpoint Research公布的最新报告,2023年第2季度中国智能手机销量同比下降4%,创新自2014年以来第2季度销量新低。报
  • 引领旗舰级影像能力向中端机普及 OPPO K11 系列发布 1799 元起

    7月25日,OPPO正式发布K系列新品—— OPPO K11 。此次 K11 在中端手机市场长期被忽视的影像板块发力,突破性地搭载索尼 IMX890 旗舰大底主摄,支持 OIS
  • 三翼鸟智能家居亮相电博会,让用户体验更真实

    2021电博会在青岛国际会展中心开幕中,三翼鸟直接把“家”搬到了现场,成为了展会的一大看点。这也是三翼鸟继9月9日发布了行业首个一站式定制智慧家平台后的
Top