varargs 매개 변수를 통한 가능한 힙 오염


433

나는 일반적인 유형의 varargs를 사용할 때 Java 7에서 발생한다는 것을 이해합니다.

하지만 내 질문은 ..

"사용하면 잠재적으로 힙을 오염시킬 수있다"고 말할 때 Eclipse는 정확히 무엇을 의미합니까?

새로운 @SafeVarargs주석은 어떻게 이것을 방지합니까?




나는 이것을 내 편집자에서보고있다 :Possible heap pollution from parameterized vararg type
Alexander Mills

답변:


252

힙 오염은 기술 용어입니다. 가리키는 객체의 상위 유형이 아닌 유형을 가진 참조를 나타냅니다.

List<A> listOfAs = new ArrayList<>();
List<B> listOfBs = (List<B>)(Object)listOfAs; // points to a list of As

이것은 "설명 할 수없는"을 초래할 수 있습니다 ClassCastException.

// if the heap never gets polluted, this should never throw a CCE
B b = listOfBs.get(0); 

@SafeVarargs이것을 막지 않습니다. 그러나 아마도 힙을 오염시키지 않는 방법이 있습니다. 컴파일러는 단지 그것을 증명할 수 없습니다. 이전에는 이러한 API를 호출 한 사람에게는 완전히 무의미하지만 모든 호출 사이트에서 억제해야하는 성가신 경고가 표시되었습니다. 이제 API 작성자는 선언 사이트에서 한 번 억제 할 수 있습니다.

이 방법은 실제로 그러나, 하지 안전, 사용자는 더 이상 경고되지 않습니다.


2
우리는 힙이 오염되었다고 말하고 있습니다. 왜냐하면 우리가 예상하지 못한 유형의 참조를 포함하고 있기 때문입니다. (귀하의 예제에서 목록 <B> 대 목록 <A>)
헤르츠 스프룽


30
이 답변은 힙 오염이 무엇인지에 대한 자세한 설명이지만 varargs가 왜 특정 경고를 보증 할 수 있는지를 설명하지는 않습니다.
Dolda2000

4
나 역시, 나는 어떻게 내 코드는이 문제를 포함하지 않도록하는 정보를 누락 (예를 들어, 어떻게 그것이 @SafeVarargs를 추가 할만큼 강화 된 것 알고있다.)
다니엘 알더

237

선언 할 때

public static <T> void foo(List<T>... bar) 컴파일러는 그것을

public static <T> void foo(List<T>[] bar) 다음에

public static void foo(List[] bar)

그러면 목록에 잘못된 값을 잘못 할당하면 컴파일러에서 오류가 발생하지 않을 위험이 있습니다. 예를 들어, Tis String이면 다음 코드는 오류없이 컴파일되지만 런타임에 실패합니다.

// First, strip away the array type (arrays allow this kind of upcasting)
Object[] objectArray = bar;

// Next, insert an element with an incorrect type into the array
objectArray[0] = Arrays.asList(new Integer(42));

// Finally, try accessing the original array. A runtime error will occur
// (ClassCastException due to a casting from Integer to String)
T firstElement = bar[0].get(0);

이러한 취약점을 포함하지 않는 방법을 검토 한 경우 @SafeVarargs경고를 표시 하지 않도록 주석을 추가 할 수 있습니다 . 인터페이스의 경우을 사용하십시오 @SuppressWarnings("unchecked").

이 오류 메시지가 표시되면

Varargs 방법으로 수정할 수없는 varargs 매개 변수에서 힙 오염이 발생할 수 있음

그리고 당신은 당신의 사용법이 안전하다는 것을 확신하고 @SuppressWarnings("varargs")대신에 사용해야 합니다. @SafeVarargs가이 방법에 적합한 주석입니까?를 참조하십시오 . https://stackoverflow.com/a/14252221/14731 오류의 두 번째 종류의 좋은 설명합니다.

참고 문헌 :


2
잘 이해하고 있다고 생각합니다. varargs를에 캐스팅하면 위험이 따릅니다 Object[]. 에 캐스팅하지 않는 한 Object[]괜찮을 것 같습니다.
djeikyb

3
어리석은 일의 예로서 다음과 같이 할 수 static <T> void bar(T...args) { ((Object[])args)[0] = "a"; }있습니다. 그런 다음로 전화하십시오 bar(Arrays.asList(1,2));.
djeikyb

1
@djeikyb 위험이 발생하면 Object[]컴파일러가 경고 메시지를 표시하지 않으면 왜 경고를 트리거합니까? 결국 컴파일 타임에이를 확인하는 것이 상당히 쉬워야합니다 (유사한 서명이있는 다른 함수에 전달하지 않으면 다른 함수가 경고를 트리거해야합니다). 나는 이것이 정말로 경고의 핵심이라고 생각하지 않으며 ( "주조하지 않으면 안전하다"), 나는 어떤 경우에 나는 괜찮은지를 여전히 이해하지 못한다.
Qw3ry

5
@djeikyb 매개 변수화 된 변수 (예 :)없이 정확하게 똑같은 바보 같은 일을 할 수 있습니다 bar(Integer...args). 그렇다면이 경고의 요점은 무엇입니까?
Vasiliy Vlasov 2016 년

3
@VasiliyVlasov이 문제는 매개 변수가있는 varargs에만 해당됩니다. 유형이 지정되지 않은 배열에서 동일한 작업을 수행하려고하면 런타임에 배열에 잘못된 유형을 삽입하지 못하게됩니다. 컴파일러는 런타임에 매개 변수 유형을 알 수 없기 때문에 런타임이 잘못된 동작을 막을 수 없다는 경고를 표시합니다 (반복적으로 배열 런타임에 제네릭이 아닌 요소의 유형을 알고 있음).
Gili

8

@SafeVarargs 이를 방지하지는 않지만 컴파일러는이를 사용하는 코드를 컴파일 할 때 더 엄격해야합니다.

http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html 에서 자세히 설명합니다.

힙 오염은 ClassCastException일반 인터페이스에서 작업을 수행 할 때 발생하는 것으로 선언 된 것과 다른 유형을 포함합니다.


사용에 대한 추가 컴파일러 제한은 특별히 관련이없는 것으로 보입니다.
Paul Bellora

6

varargs를 사용하면 Object[] 하면 인수를 보유 .

이스케이프 분석으로 인해 JIT는이 어레이 생성을 최적화 할 수 있습니다. (내가 찾은 몇 번 중 하나) 최적화되지는 않지만 메모리 프로파일 러에 문제가 없으면 걱정하지 않아도됩니다.

AFAIK @SafeVarargs는 컴파일러의 경고를 표시하지 않으며 JIT의 작동 방식을 변경하지 않습니다.


6
에 대한 그의 질문에 실제로 대답하지는 않지만 흥미 롭습니다 @SafeVarargs.
Paul Bellora

1
아니. 그것은 힙 오염이 아닙니다. "힙 오염은 매개 변수화 된 유형의 변수가 해당 매개 변수화 된 유형이 아닌 개체를 참조 할 때 발생합니다." 참조 : docs.oracle.com/javase/tutorial/java/generics/…
Doradus

1

그 이유는 varargs가 매개 변수화되지 않은 객체 배열로 호출되는 옵션을 제공하기 때문입니다. 따라서 타입이 List <A> ...이면, Varargs가 아닌 List [] 타입으로도 호출 할 수 있습니다.

예를 들면 다음과 같습니다.

public static void testCode(){
    List[] b = new List[1];
    test(b);
}

@SafeVarargs
public static void test(List<A>... a){
}

보시다시피 List [] b는 모든 유형의 소비자를 포함 할 수 있지만이 코드는 컴파일됩니다. varargs를 사용하면 괜찮지 만 유형 삭제 후 메소드 정의를 사용하면 void test (List [])-컴파일러는 템플릿 매개 변수 유형을 확인하지 않습니다. @SafeVarargs는이 경고를 표시하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.