Java 8에서 ArrayList의 기본 용량이 이제 0 인 이유는 무엇입니까?
내가 기억 하듯이 Java 8 이전에는 기본 용량 ArrayList
이 10이었습니다.
놀랍게도 기본 (무효) 생성자에 대한 주석은 여전히 다음과 같이 말합니다. Constructs an empty list with an initial capacity of ten.
에서 ArrayList.java
:
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
...
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
기술적 10
으로는 백업 어레이의 지연 초기화를 인정하면 0이 아니라. 보다:
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
어디
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
당신이 말하는 것은 처음에 비어있는 모든 ArrayList
객체 사이에서 공유되는 0 크기의 초기 배열 객체입니다 . 즉, Java 7에도 존재하는 최적화 인 용량이 느리게10
보장 됩니다.
물론 생성자 계약이 완전히 정확하지는 않습니다. 아마도 이것이 혼란의 원인 일 것입니다.
배경
Mike Duigou의 이메일입니다.
빈 ArrayList 및 HashMap 패치의 업데이트 된 버전을 게시했습니다.
http://cr.openjdk.java.net/~mduigou/JDK-7143928/1/webrev/
이 개정 된 구현은 두 클래스에 새로운 필드 를 도입 하지 않습니다 . ArrayList의 경우 백업 배열의 지연 할당은 목록이 기본 크기로 생성 된 경우에만 발생합니다. 성능 분석 팀에 따르면 ArrayList 인스턴스의 약 85 %가 기본 크기로 생성되므로이 최적화는 대부분의 경우에 유효합니다.
For HashMap, creative use is made of the threshold field to track the requested initial size until the bucket array is needed. On the read side the empty map case is tested with isEmpty(). On the write size a comparison of (table == EMPTY_TABLE) is used to detect the need to inflate the bucket array. In readObject there's a little more work to try to choose an efficient initial capacity.
From: http://mail.openjdk.java.net/pipermail/core-libs-dev/2013-April/015585.html
In java 8 default capacity of ArrayList is 0 until we add at least one object into the ArrayList object (You can call it lazy initialization).
Now question is why this change has been done in JAVA 8?
Answer is to save memory consumption. Millions of array list objects are created in real time java applications. Default size of 10 objects means that we allocate 10 pointers (40 or 80 bytes) for underlying array at creation and fill them in with nulls. An empty array (filled with nulls) occupy lot of memory .
Lazy initialization postpones this memory consumption till moment you will actually use the array list.
Please see below code for help.
ArrayList al = new ArrayList(); //Size: 0, Capacity: 0
ArrayList al = new ArrayList(5); //Size: 0, Capacity: 5
ArrayList al = new ArrayList(new ArrayList(5)); //Size: 0, Capacity: 0
al.add( "shailesh" ); //Size: 1, Capacity: 10
public static void main( String[] args )
throws Exception
{
ArrayList al = new ArrayList();
getCapacity( al );
al.add( "shailesh" );
getCapacity( al );
}
static void getCapacity( ArrayList<?> l )
throws Exception
{
Field dataField = ArrayList.class.getDeclaredField( "elementData" );
dataField.setAccessible( true );
System.out.format( "Size: %2d, Capacity: %2d%n", l.size(), ( (Object[]) dataField.get( l ) ).length );
}
Response: -
Size: 0, Capacity: 0
Size: 1, Capacity: 10
Article Default capacity of ArrayList in Java 8 explains it in details.
If the very first operation that is done with an ArrayList is to pass addAll
a collection which has more than ten elements, then any effort put into creating an initial ten-element array to hold the ArrayList's contents would be thrown out the window. Whenever something is added to an ArrayList it's necessary to test whether the size of the resulting list will exceed the size of the backing store; allowing the initial backing store to have size zero rather than ten will cause this test to fail one extra time in the lifetime of a list whose first operation is an "add" which would require creating the initial ten-item array, but that cost is less than the cost of creating a ten-item array that never ends up getting used.
That having been said, it might have been possible to improve performance further in some contexts if there were a overload of "addAll" which specified how many items (if any) would likely be added to the list after the present one, and which could use that to influence its allocation behavior. In some cases code which adds the last few items to a list will have a pretty good idea that the list is never going to need any space beyond that. There are many situations where a list will get populated once and never modified after that. If at the point code knows that the ultimate size of a list will be 170 elements, it has 150 elements and a backing store of size 160, growing the backing store to size 320 will be unhelpful and leaving it at size 320 or trimming it to 170 will be less efficient than simply having the next allocation grow it to 170.
The question is 'why?'.
Memory profiling inspections (for example (https://www.yourkit.com/docs/java/help/inspections_mem.jsp#sparse_arrays) shows that empty (filled with nulls) arrays occupy tons of memory .
Default size of 10 objects means that we allocate 10 pointers (40 or 80 bytes) for underlying array at creation and fill them in with nulls. Real java applications create millions of array lists.
The introduced modification removes^W postpone this memory consumption till moment you will actually use the array list.
ArrayList default size in JAVA 8 is stil 10. The only change made in JAVA 8 is that if a coder adds elements less than 10 then the remaining arraylist blank places are not specified to null. Saying so because I have myself gone through this situation and eclipse made me look into this change of JAVA 8.
You can justify this change by looking at below screenshot. In it you can see that ArrayList size is specified as 10 in Object[10] but the number of elements displayed are only 7. Rest null value elements are not displayed here. In JAVA 7 below screenshot is same with just a single change which is that the null value elements are also displayed for which the coder needs to write code for handling null values if he is iterating complete array list while in JAVA 8 this burden is removed from the head of coder/developer.
After above question I gone through ArrayList Document of Java 8. I found the default size is still 10 only.
'developer tip' 카테고리의 다른 글
MySQL "WITH"절 (0) | 2020.09.12 |
---|---|
Java에서 Linux 쉘 명령을 호출하는 방법 (0) | 2020.09.12 |
NHibernate의 역 속성 (0) | 2020.09.12 |
표준 라이브러리의 어떤 기능을 피해야합니까? (0) | 2020.09.12 |
@OneToMany List <> 대 Set <> 차이점 (0) | 2020.09.12 |