成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

終于明白為啥面試老是有人問 SubList 了,原來這玩意會 OOM!

開發 前端
在初始化內部類 SubList 的時候傳入了 this,這個 SubList 中的 parent 字段就是原始的 List,初始化的時候,并沒有把原始 List 中的元素復制到獨立的變量中保存,所以雙方對元素的修改都會互相影響。而且 SubList 強引用了原始的 List,所以大量保存這樣的 SubList 其實也保存了大量原始的 List,從而導致 OOM。

最近剛做到一個內存分頁的需求,自測了幾次就 OOM 了,找了半天原因,終于把這個坑填上來,下面整理一下發出來,各位小伙伴引以為鑒。

我們經常會使用 List.subList 方法對 List 進行切片,比如取前十個元素出來用,但是和 Arrays.asList 的問題類似(具體文章可以看 慎用 ArrayList,全是坑!),List.subList 返回的子 List 不是一個全新地址的 ArrayList,這個子 List 會和原始 List 相互影響。

如果不注意,很可能會因此產生 OOM 問題。

話不多說,先復現問題。如下代碼所示,定義一個名為 data 的靜態 List 用來存放 List<Integer> 類型,循環 1000 次,每次都從一個具有 100 萬個 Integer 的 List 中(即代碼中的 rawList),使用 subList 方法獲得一個只包含一個數字的子 List,并把這個子 List 加入 data 變量:

圖片圖片

看起來,這個 data 變量里面最終保存的只是 1000 個具有 1 個元素的 List 而已,并不會出現什么問題啊。

但是,代碼在運行到一段時間后,可以看到在我的機器上是第 159 次循環后發生了 OOM:

圖片圖片

出現 OOM 的原因是,循環中的 1000 個具有 100 萬個元素的 List 始終得不到回收,因為它始終被 subList 方法返回的 List 強引用。

subList 返回的子 List 為啥會強引用原始的 List?再來做個實驗看下:

首先初始化一個包含數字 1 到 10 的 ArrayList,然后通過調用 subList 方法取出 2、3、4,隨后刪除這個 SubList 中的元素數字 3。可以看到原始 List 中數字 3 被刪除了,說明刪除子 List 中的元素影響到了原始 List:

圖片圖片

圖片圖片

繼續看,我們為原始的 ArrayList 增加一個元素數字 0,然后遍歷 SubList 輸出所有元素。代碼運行后報錯 java.util.ConcurrentModificationException:

圖片圖片

圖片圖片

分析下 ArrayList 的源碼,看看為什么會是這樣:

圖片圖片

  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 會相互影響,那么避免相互影響的修復方式有兩種:

  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());


責任編輯:武曉燕 來源: 飛天小牛肉
相關推薦

2021-06-13 12:03:46

SaaS軟件即服務

2021-10-09 00:02:04

DevOps敏捷開發

2022-03-27 20:32:28

Knative容器事件模型

2021-10-17 20:38:30

微服務內存組件

2021-03-25 11:24:25

爬蟲技術開發

2020-11-03 07:04:39

云計算公有云私有云

2021-08-31 19:14:38

技術埋點運營

2022-04-27 18:25:02

數據采集維度

2021-12-03 18:25:56

數據指標本質

2021-10-12 18:31:40

流量運營前端

2021-09-03 18:38:13

數據湖數據倉庫

2021-03-03 21:31:24

量化投資利潤

2022-01-05 18:27:44

數據挖掘工具

2021-06-29 11:21:41

數據安全網絡安全黑客

2020-11-30 08:34:44

大數據數據分析技術

2022-04-22 11:26:55

數據管理架構

2021-02-14 00:21:37

區塊鏈數字貨幣金融

2022-07-31 20:29:28

日志系統

2022-04-12 18:29:41

元數據系統架構

2021-09-26 15:58:05

MySQL SQL 語句數據庫
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: www.欧美 | 国产成人久久 | 91精品在线播放 | 国产成人精品免费 | 黄网址在线观看 | 午夜视频大全 | 免费看a | 91新视频 | 久久综合av | 午夜天堂精品久久久久 | 成人影院网站ww555久久精品 | 亚洲精品乱码 | 久久久天堂 | 一级一级毛片免费看 | www.4hu影院 | 日韩在线免费视频 | 亚洲欧洲在线视频 | 三级免费网 | 国产精品一区二区久久 | 韩日av在线 | 91麻豆精品国产91久久久资源速度 | 国产高清视频在线观看 | 欧美精品久久 | 精品日韩一区 | 亚洲一区二区久久 | 中国黄色毛片视频 | 欧美一区2区三区4区公司二百 | 国产精品视频免费观看 | 欧美精品在线免费 | 99久久久国产精品免费消防器 | 国产成人一区二区三区精 | 中文在线一区二区 | 免费欧美 | 欧美日韩精品久久久免费观看 | 亚洲视频精品在线 | 日韩视频在线观看一区二区 | 精品一二区 | 成人欧美一区二区 | 色爱综合网 | 亚洲精品日韩综合观看成人91 | 欧美黄色网 |