当前位置:网站首页>ArrayList # sublist these four holes, you get caught accidentally
ArrayList # sublist these four holes, you get caught accidentally
2022-06-24 11:34:00 【Hollis Chuang】
Hollis In the limited time discount for your new book , An in-depth explanation Java Basic dry goods notes !
One 、 Memory leak caused by improper use
Let's first show you a simple but interesting code
public class OrderService {
public static void main(String[] args) {
OrderService orderService = new OrderService();
orderService.process();
}
public void process() {
List<Long> orderIdList = queryOrder();
List<List<Long>> allFailedList = new ArrayList<>();
for(int i = 0; i < Integer.MAX_VALUE; i++) {
System.out.println(i);
List<Long> failedList = doProcess(orderIdList);
allFailedList.add(failedList);
}
}
private List<Long> doProcess(List<Long> orderIdList) {
List<Long> failedList = new ArrayList<>();
for (Long orderId : orderIdList) {
if (orderId % 2 == 0) {
failedList.add(orderId) ;
}
}
// Take only one failed order id Do analysis
return failedList.subList(0, 1);
}
private List<Long> queryOrder() {
List<Long> orderIdList = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
orderIdList.add(RandomUtils.nextLong());
}
return orderIdList;
}
} If you run this code on a local machine , And turn on arthas Monitor memory conditions :
Memory used total max usage
heap 2742M 3643M 3643M 75.28%
ps_eden_space 11M 462M 468M 2.52%
ps_survivor_space 0K 460288K 460288K 0.00%
ps_old_gen 2730M 2731M 2731M 99.99%
nonheap 28M 28M -1 97.22%
code_cache 5M 5M 240M 2.19%
metaspace 20M 20M -1 97.19%
compressed_class_space 2M 2M 1024M 0.25%
direct 0K 0K - 0.00%
mapped 0K 0K - 0.00% Less than 3GB Old age pawn i Cycle to about 60 It exploded when it was around 10000 , The largest object in our current heap is allFailedList At most 60 m Long Type List, Roughly, there are only a few dozen MB, It will not explode the memory at all . Then we have reason to suspect that the above code has a memory leak .
go back to ArrayList#subList Implementation code :
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
private class SubList extends AbstractList<E> implements RandomAccess {
private final AbstractList<E> parent;
private final int parentOffset;
private final int offset;
int size;
SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
} You can see , Every time you call ArrayList#subList It will generate a SubList object , And this object's parent The attribute value holds the original ArrayList References to , This makes sense ,allFailedList Hold all previous calls queryOrder Produced List object , These objects are eventually transferred to the elderly generation without release .
Two 、 Improper use causes dead circulation
Let's look at another piece of code :
public class SubListDemo {
public static void main(String[] args) {
List<Long> arrayList = init();
List<Long> subList = arrayList.subList(0, 1);
for (int i = 0; i < arrayList.size(); i++) {
if (arrayList.get(i) % 2 == 0) {
subList.add(arrayList.get(i));
}
}
}
private static List<Long> init() {
List<Long> arrayList = new ArrayList<>();
arrayList.add(RandomUtils.nextLong());
arrayList.add(RandomUtils.nextLong());
arrayList.add(RandomUtils.nextLong());
arrayList.add(RandomUtils.nextLong());
arrayList.add(RandomUtils.nextLong());
return arrayList;
}
} If I say that the above code is an endless loop , Would you be surprised . go back to subList The implementation of the
// AbstractList
public boolean add(E e) {
add(size(), e);
return true;
} Then it will call ArrayList Methods
public void add(int index, E e) {
rangeCheckForAdd(index);
checkForComodification();
parent.add(parentOffset + index, e);
this.modCount = parent.modCount;
this.size++;
} You can see , call subList Of add In fact, it is in the original ArrayList Add elements , Therefore, the original arrayList.size() Will always get bigger , Eventually lead to a dead cycle .
3、 ... and 、 Be able to subList Heyuan List Make structural changes
public static void main(String[] args) {
List<String> listArr = new ArrayList<>();
listArr.add("Delhi");
listArr.add("Bangalore");
listArr.add("New York");
listArr.add("London");
List<String> listArrSub = listArr.subList(1, 3);
System.out.println("List-: " + listArr);
System.out.println("Sub List-: " + listArrSub);
//Performing Structural Change in list.
listArr.add("Mumbai");
System.out.println("\nAfter Structural Change...\n");
System.out.println("List-: " + listArr);
System.out.println("Sub List-: " + listArrSub);
} This code will eventually throw ConcurrentModificationException
List-: [Delhi, Bangalore, New York, London]
Sub List-: [Bangalore, New York]
After Structural Change...
List-: [Delhi, Bangalore, New York, London, Mumbai]
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1231)
at java.util.ArrayList$SubList.listIterator(ArrayList.java:1091)
at java.util.AbstractList.listIterator(AbstractList.java:299)
at java.util.ArrayList$SubList.iterator(ArrayList.java:1087)
at java.util.AbstractCollection.toString(AbstractCollection.java:454)
at java.lang.String.valueOf(String.java:2982)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at infosys.Research.main(Research.java:26) Look at the simple ArrayList Source code :
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
// Note that this line is correct for the original list Of modCount This variable is incremented
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
} it is to be noted that , Call the... Of the original array add Method has modified the original array modCount attribute , When the program is executed to print subList This line of code calls Sublist#toString Method , Finally, the following private method will be called :
private void checkForComodification() {
if (ArrayList.this.modCount != this.modCount)
throw new ConcurrentModificationException();
} According to the previous analysis , primary ArrayList Of modCount The attribute has been self incremented , therefore ArrayList.this.modCount != this.modCount The result of the execution is true, And then eventually it sold out ConcurrentModificationException abnormal .
About modCount This attribute ,Oracle There is also a detailed description in the document
The number of times this list has been structurally modified. Structural modifications are those that change the size of the list.
Which translates as :
modCount The record is List Number of structural modifications , The so-called structural modification refers to the ability to change List Size operation
If there is no knowledge reserve in advance , This kind of abnormality is difficult to check
Four 、 As RPC Serialization failed when the interface enters parameters
From above SubList You can see the definition of ,SubList It didn't happen Serializable Interface , So in some dependencies Java Native serialization protocol RPC Serialization fails in the framework of , Such as Dubbo etc. .
5、 ... and 、 Best practices
subList The original design List A view of , It is often used in read-only scenarios , This is different from what most people understand , Even if only used in read-only scenarios , It is also prone to memory leaks , Moreover, the existence of this view does not allow the original List and SubList Make structural changes , Personally think that subList This Api The design of the is terrible , Try to avoid using... Directly in your code ArrayList#subList, obtain List Of subList There are two best practices :
5.1 Copy to the new ArrayList in
ArrayList myArrayList = new ArrayList();
ArrayList part1 = new ArrayList(myArrayList.subList(0, 25));
ArrayList part2 = new ArrayList(myArrayList.subList(26, 51));5.2 Use lambda expression
dataList.stream().skip(5).limit(10).collect(Collectors.toList());
dataList.stream().skip(30).limit(10).collect(Collectors.toList());End
My new book 《 In depth understanding of Java The core technology 》 It's on the market , After listing, it has been ranked in Jingdong best seller list for several times , At present 6 In the discount , If you want to start, don't miss it ~ Long press the QR code to buy ~

Long press to scan code and enjoy 6 A discount
Previous recommendation
3000 Frame animation illustration MySQL Why binlog、redo log and undo log
It's a hot topic : a monthly salary 2~3W The Manon of , How to spend the day ?
In terms of implementation principle ,Nacos Why so strong
There is Tao without skill , It can be done with skill ; No way with skill , Stop at surgery
Welcome to pay attention Java Road official account

Good article , I was watching ️
边栏推荐
- Multi gate mixture of experts and code implementation
- Install Kali on the U disk and persist it
- Axi low power interface
- Group counting_ Structure and workflow of CPU
- Beauty of script │ VBS introduction interactive practice
- Anonymous Messenger: hidden communication of Trojan horse
- "One good programmer is worth five ordinary programmers!"
- Programmers spend most of their time not writing code, but...
- Programmers spend most of their time not writing code, but...
- 【老卫搞机】090期:键盘?主机?全功能键盘主机!
猜你喜欢
随机推荐
What code did the full stack programmer write this month?
[Architect (Part 41)] installation of server development and connection to redis database
Reliable remote code execution (1)
The record of 1300+ times of listing and the pursuit of ultimate happiness
Realization of alarm clock with AHK
How does wechat and QQ chat work? So simple!!!
【数字IC/FPGA】Booth乘法器
Déplacer Tencent sur le cloud a guéri leur anxiété technologique
PPT绘图相关,快捷键,美观度
Reading at night -- about microservices and containers
[latest - lightweight cloud servers - hot sales] new lightweight application server optimization scheme, 1-core 2g5m time limit as low as 99 yuan / year
≥ 2012r2 configure IIS FTP
保险APP适老化服务评测分析2022第06期
Shell脚本(.sh文件)如何执行完毕之后不自动关闭、闪退?
我真傻,招了一堆只会“谷歌”的程序员!
Why choose b+ tree as storage engine index structure
【毕业季·进击的技术er】绕树三匝,何枝可依?
Tke deployment kubord
打新债可以申请多少 开户是安全的吗
I pushed my younger brother into Tencent. Look at his benchmark resume!






![[activities this Saturday] NET Day in China](/img/33/c0e8eeb8f673232a7c27bbaf5e713f.jpg)




