Java에서 객체 생성을 피해야합니까?


243

동료에게 Java 객체 생성에서 수행 할 수있는 가장 비싼 작업이라고 들었습니다. 따라서 가능한 한 적은 수의 객체를 만드는 것으로 결론을 내릴 수 있습니다.

이것은 객체 지향 프로그래밍의 목적을 다소 어기는 것 같습니다. 객체를 만들지 않으면 최적화를 위해 하나의 긴 클래스 C 스타일을 작성하고 있습니까?


39
"자바 객체 생성은 수행 할 수있는 가장 비싼 작업 입니다. " 그 주장의 근원을 공유하고 있습니까?
Songo

92
그리고-무엇에 비해 가장 비싼 작업? pi를 900 자리로 계산하거나 int를 증가시키는 것과 비교할 때?
jasonk

4
그들이 특정 객체 생성의 특정 부분에 대해 이야기했을 수도 있습니까? Apple이 tableViewCells 대기열을 어떻게 사용하는지 생각하고 있습니다. 아마도 동료가 특정 객체와 관련된 약간의 오버 헤드로 인해 몇 개의 객체를 생성하여 재사용하라고 제안했을까요? 그들이 왜 그런 주장을하는지 알아 내려고 노력했습니다.
Tyler DeWitt

3
이것은 내가 프로그래밍에 대해 들어 본 것 중 가장 재미있는 것 중 하나입니다.)
Mert Akcakaya

22
산술도 꽤 비싸다. 우리는 계산을 피해야한다. 아, JVM을 시작하는 것은 정말 비싸므로 어떤 JVM도 시작하지 않아야한다 :-).
제임스 앤더슨

답변:


478

동료가 무슨 말을하는지 모릅니다.

가장 비싼 작업은 듣고 있습니다 . 그들은 당신에게 시간을 낭비하고 (이 답변이 게시 된 날짜 기준으로) 10 년이 지난 정보에 오도하고 여기에 게시하고 진실을 위해 인터넷을 연구하는 데 시간을 소비해야합니다.

그들이 10 년 전에 읽거나 읽은 것을 무지하게 역류시키고 더 이상 잘 모를 수 있기를 바랍니다. 나는 그들이 의심하는 다른 것을 취할 것입니다. 이것은 어느 쪽이든 최신 상태를 유지하는 사람에게는 잘 알려진 오류입니다.

모든 것이 객체입니다 (제외 primitives)

기본 요소 ( int, long, double등) 이외의 모든 것은 Java의 오브젝트입니다. Java에서 오브젝트 작성을 피할 수있는 방법은 없습니다.

대부분의 경우 메모리 할당 전략으로 인해 Java로 객체를 생성하는 것이 C ++보다 빠르며, 모든 실제적인 목적으로 JVM의 다른 모든 것에 비해 "무료" 로 간주 될 수 있습니다 .

1990 년대 후반 2000 년대 초반 JVM 구현은 실제 객체 할당에서 약간의 성능 오버 헤드를 가졌습니다. 2005 년 이후로는 그렇지 않았습니다.

-Xms응용 프로그램을 올바르게 실행하는 데 필요한 모든 메모리를 지원하도록 조정 하면 GC가 최신 GC 구현에서 대부분의 가비지를 실행하고 스윕 할 필요가 없으며 수명이 짧은 프로그램은 GC를 전혀 사용하지 않을 수 있습니다.

어쨌든 빨간색 청어 인 여유 공간을 사용하려고 시도하지 않고 런타임 성능을 최대화합니다. 즉, JVM 힙이 항상 거의 100 % 할당됨을 의미합니다. 여유 JVM 힙 메모리는 어쨌든 앉아있는 것을 제공하지 않습니다.

GC가 유용한 방법으로 나머지 시스템에 메모리를 다시 확보 할 것이라는 오해가 있습니다. 이것은 완전히 잘못된 것입니다!

JVM 힙은 커지거나 줄어들지 않으므로 나머지 시스템은 JVM 힙의 여유 메모리 의해 긍정적 인 영향을받습니다 . -Xms시작시 지정된 모든 것을 할당하며 휴리스틱은 해당 메모리 인스턴스를 실제로 OS로 다시 릴리스하여 JVM 인스턴스가 완전히 종료 될 때까지 다른 OS 프로세스와 공유되도록하는 것입니다. -Xms=1GB -Xmx=1GB주어진 시간에 실제로 생성되는 객체 수에 관계없이 1GB의 RAM을 할당합니다. 힙 메모리의 백분율을 해제 할 수있는 몇 가지 설정이 있지만 모든 실제적인 목적 으로 JVM은이 메모리를 충분히 릴리스 할 수 없습니다.따라서 다른 프로세스가이 메모리를 회수 할 수 없으므로 나머지 시스템은 JVM 힙이 해제 되어도 이점이 없습니다. 이에 대한 RFE는 2006 년 11 월 29 일 에 "수락" 되었지만 그에 대한 조치는 없었습니다. 이것은 권한이있는 사람에게는 문제가되지 않습니다.

수명이 짧은 작은 객체를 많이 만들면 JVM이 오랫동안 일시 중지된다는 잘못된 생각이 있습니다.

현재 GC 알고리즘은 실제로 수명이 짧은 많은 작은 객체를 만드는 데 최적화 되어 있으며 기본적으로 모든 프로그램에서 Java 객체의 99 % 휴리스틱입니다. 객체 풀링 을 시도 하면 실제로 대부분의 경우 JVM 성능이 저하됩니다.

오늘날 풀링이 필요한 유일한 객체 는 JVM 외부의 유한 리소스를 참조하는 객체입니다 . 소켓, 파일, 데이터베이스 연결 등을 재사용 할 수 있습니다. 일반 객체는 메모리 위치에 직접 액세스 할 수있는 언어와 같은 의미로 풀링 할 수 없습니다 . 객체 캐싱 은 다른 개념이며 일부 사람들이 순진하게 풀링 이라고 부르는 것일 수도 있고 아닐 수도 있습니다 . 두 개념은 같지 않으므로 혼동해서는 안됩니다.

최신 GC 알고리즘은 일정에 할당을 해제하지 않고 특정 세대에 여유 메모리가 필요할 때 할당을 해제하기 때문에이 문제가 없습니다. 힙이 충분히 큰 경우 일시 중지를 유발할만큼 오랫동안 할당 해제가 발생하지 않습니다.

객체 지향 동적 언어는 오늘날에도 계산에 민감한 테스트에서 C를 능가하고 있습니다.


274
+1 : "가장 비싼 작업은들을 것입니다." 한동안 들어 본 것 중에서 최고입니다.
rjnilsson

21
@DeadMG는 누적 GC 오버 헤드에서도 Java 가 C ++보다 빠를 있습니다 (예 : 힙 압축으로 인해 특정 데이터 구조에 대한 캐시 누락 최소화).
SK-logic

13
@ SK-logic : GC가 결정적이지 않기 때문에 실제로이를 증명하는 것은 매우 어렵습니다. 캐시 누락을 최소화하는 것과 같이 모든 객체가 다른 간접적이어야 할 때 캐시 공간을 낭비하고 실행 시간을 늘리는 것은 어렵습니다. 그러나 객체 풀이나 메모리 영역과 같은 C ++에서 적절한 할당자를 사용하면 가비지 수집기의 성능을 쉽게 맞추거나 능가 할 수 있다고 주장합니다. 예를 들어 _alloca, 할부 상환 보다 빠르게 수행되는 메모리 아레나 클래스를 작성할 수 있습니다 .
DeadMG

33
객체 생성이 예전보다 저렴 해졌습니다. 그래도 무료는 아닙니다. 거짓말하는 사람은 그리고 C를 두드리는 OO 언어에 대한 링크는 진정으로 배우려고하는 누군가에게 과장된 반응입니다.
jasonk

17
이런 종류의 답변 때문에 우리는 엉터리 코드로 끝납니다. 정답은 Java로 객체를 생성하는 것이 Java 객체를 생성하고 초기화하는 것입니다. 첫 번째 부분은 저렴하고 두 번째 부분은 매우 비쌀 있습니다. 사람들은 new핫스팟 에서 키워드를 사용하기 전에 항상 생성자에서 발생하는 일을 살펴 봐야 합니다. 사람들 이 Swing 객체 new ImageIcon(Image)paint()메소드 에서 사용하는 것을 보았습니다. 꽤 비싸고 전체 UI를 매우 부진하게 만들고있었습니다. 따라서 흑백 답변이 아닙니다 new. 어딘가에서 사용하기 전에 생각하십시오 .
qwertzguy

94

결론 : 객체를 생성하는 지름길을 취하기 위해 디자인을 손상시키지 마십시오. 불필요하게 객체를 만들지 마십시오. 합리적인 경우 중복 작업 (모든 종류)을 피하도록 설계하십시오.

대부분의 답변과 달리-객체 할당 DOES에는 관련 비용이 있습니다. 저렴한 비용이지만 불필요한 객체를 만들지 않아야합니다. 코드에서 불필요한 것을 피해야하는 것과 같습니다. 큰 객체 그래프는 GC를 느리게 만들고, 더 많은 메소드 호출이 필요하고, CPU 캐시 누락이 더 많이 발생하며, RAM이 적은 경우 프로세스가 디스크로 스왑 될 가능성이 높아짐에 따라 실행 시간이 더 길다는 것을 의미합니다.

누군가가 이것이 최첨단 사례임을 알리기 전에-최적화하기 전에 ~ 50 행의 데이터를 처리하기 위해 20 + MB의 객체를 만든 응용 프로그램을 프로파일 링했습니다. 분당 최대 100 개의 요청을 확장하고 갑자기 분당 2GB의 데이터를 생성 할 때까지 테스트에 적합합니다. 초당 20 회 요청을하려면 400MB의 객체를 생성 한 다음 버립니다. 괜찮은 서버의 경우 20 reqs / sec는 작습니다.


7
정말 코드의 명확성의 관점에서 차이가 없습니다 어떤 경우에는 있지만 성능이 다소 큰 차이를 만들 수 있습니다 : 나는 예를 추가 할 수 있습니다 스트림에서 읽을 때, 예를 들어, 뭔가를 사용하는 것은 드문 일이 아니다 같이 while(something) { byte[] buffer = new byte[10240]; ... readIntoBuffer(buffer); ...하는 수도 예를 들어 byte[] buffer = new byte[10240]; while(something) { ... readIntoBuffer(buffer); ....
JimmyB

4
+1 : 불필요한 객체 생성 (또는 제거 후 정리)은 때때로 비용이 많이들 수 있습니다. Java의 3D 그래픽 / OpenGL 코드는 GC가 프레임 속도에 혼란을 줄 수 있으므로 생성 된 객체 수를 최소화하기 위해 최적화를 수행 한 곳입니다.
Leo

1
와! 50 행의 데이터를 처리하는 데 20MB 이상? 미쳤어 어쨌든 그 객체는 오래 지속됩니까? 그것이 GC에 중요한 경우이기 때문입니다. 반면에 메모리 요구 사항 만 논의 하는 경우 가비지 수집 또는 개체 생성 효율성과 관련이 없습니다.
Andres F.

1
객체의 수명이 짧습니다 (일반적인 경우 0.5 초 미만). 이 쓰레기 량은 여전히 ​​성능에 영향을 미칩니다.
jasonk

2
실제로 현실에 확고한 자세를 취해 주셔서 감사합니다. 사려 깊은 건축의 영향을받는 사람이라면 누구나 관련이 있습니다.
JM Becker

60

실제로, Java 언어 (또는 다른 관리 언어)가 가능하게하는 메모리 관리 전략으로 인해 객체 생성은 어린 세대라고하는 메모리 블록에서 포인터를 증가시키는 것 이상입니다. 여유 메모리를 검색해야하는 C보다 훨씬 빠릅니다.

비용의 다른 부분은 객체 파괴이지만 C와 비교하기는 어렵습니다. 컬렉션 비용은 장기적으로 저장된 객체의 양을 기준으로하지만 콜렉션 빈도는 생성 된 객체의 양을 기준으로합니다. 결국 C 스타일 메모리 관리보다 훨씬 빠릅니다.


7
+1 가비지 수집기는 "정상 작동"하더라도 모든 Java 프로그래머는 세대 별 가비지 수집기에 대해 알아야합니다.
benzado

18
최신 버전의 Java는 이스케이프 분석을 수행 할 수 있습니다. 즉, 스택에서 메소드를 이스케이프하지 않는 오브젝트에 메모리를 할당 할 수 있으므로이를 정리할 수 있습니다. 가비지 콜렉터는 해당 오브젝트를 처리 할 필요가 없습니다. 메소드의 스택 프레임이 풀릴 때 (메소드가 반환 될 때) 자동으로 삭제됩니다.
Jesper

4
다음 단계 이탈 분석 (예를 들어 순수 레지스터 작은 객체에 대한 메모리를 "할당"하는 Point오브젝트 2 개 범용 레지스터에 들어갈 수있다).
Joachim Sauer

6
@Joachim Sauer : HotSpot VM의 최신 구현에서 수행되는 작업입니다. 이것을 스칼라 교체라고합니다.
someguy 2016 년

1
@ someguy : 나는 다음 일로 그것에 대해 읽었지만 이미 완료되었는지 확인하지 않았습니다. 우리가 이미 이것을 가지고 있다는 것을 듣는 것은 훌륭한 소식입니다.
Joachim Sauer

38

다른 포스터는 Java에서 객체 생성이 매우 빠르며 일반적인 Java 응용 프로그램에서는 일반적으로 걱정할 필요가 없다고 지적했습니다.

매우 특별한 상황의 몇 가지가 있습니다 입니다 객체 생성을 방지하는 것이 좋습니다.

  • 지연 시간에 민감한 응용 프로그램을 작성하고 GC 일시 중지를 피하려는 경우 더 많은 개체를 생성할수록 더 많은 GC가 발생하고 일시 중지 될 가능성이 높아집니다. 이것은 게임, 일부 미디어 응용 프로그램, 로봇 제어, 고주파 거래 등과 관련하여 유효한 고려 사항이 될 수 있습니다. 해결책은 필요한 모든 객체 / 배열을 미리 할당하고 재사용하는 것입니다. 이러한 종류의 기능을 제공하는 라이브러리 (예 : Javolution)가 있습니다. 그러나 논란의 여지가 있지만 대기 시간이 짧은 경우 Java 또는 C # 대신 C / C ++ / 어셈블러를 사용해야합니다. :-)
  • 박스형 프리미티브 (Double, Integer 등)를 피하는 것은 특정 상황에서 매우 유용한 미세 최적화 일 수 있습니다. 박스형 프리미티브 (double, int 등)는 객체 별 오버 헤드를 피하기 때문에 수치 처리 등과 같은 CPU 집약적 작업이 훨씬 빠릅니다. 일반적으로 프리미티브 배열은 Java에서 매우 잘 수행되므로 숫자 처리에 사용하지 말아야합니다. 다른 종류의 물체.
  • 제한된 메모리 상황 에서는 각 객체에 작은 오버 헤드 (일반적으로 JVM 구현에 따라 8-16 바이트)가 있으므로 생성 된 (활성) 객체 수를 최소화하려고합니다. 이러한 상황에서는 데이터를 저장하기 위해 많은 수의 작은 개체 대신 작은 수의 큰 개체 또는 배열을 선호해야합니다.

3
이스케이프 분석을 사용하면 수명이 짧은 (한정 수명) 오브젝트를 스택에 저장할 수 있으며 이러한 오브젝트는 무료로 ibm.com/developerworks/java/library/j-jtp09275/index.html에
Richard Tingle

1
@Richard : 훌륭한 포인트-이스케이프 분석은 아주 좋은 최적화를 제공합니다. 그래도 의존해야합니다. 모든 Java 구현 및 모든 상황에서 발생한다고 보장 할 수는 없습니다. 따라서 종종 벤치마킹하여 확인해야합니다.
mikera 2016 년

2
또한 100 % 정확한 이스케이프 분석은 정지 문제와 같습니다. 복잡한 상황에서 탈출 분석에 의존하지 마십시오. 적어도 일부 시간 동안 틀린 답을 줄 수 있습니다.
Jules

첫 번째 포인트와 마지막 포인트는 빠르게 해제되는 작은 객체에는 적용되지 않으며 eden으로 죽고 (C에서 스택 할당을 생각하면 거의 무료입니다) GC 시간이나 메모리 할당에는 영향을 미치지 않습니다. Java에서 대부분의 객체 할당은이 범주에 속하므로 본질적으로 무료입니다. 두 번째 포인트는 여전히 유효합니다.
Bill K

17

동료의 말에 진실의 핵심이 있습니다. 나는 객체 생성 문제 가 실제로 가비지 수집 이라는 것을 정중하게 제안한다 . C ++에서 프로그래머는 메모리 할당 해제 방법을 정확하게 제어 할 수 있습니다. 프로그램은 원하는만큼 길거나 짧게 쌓일 수 있습니다. 또한 C ++ 프로그램은이를 생성 한 스레드와 다른 스레드를 사용하여 crud를 폐기 할 수 있습니다. 따라서 현재 작업중인 스레드는 정리를 중단 할 필요가 없습니다.

반대로 JVM (Java Virtual Machine)은 주기적으로 코드를 중지하여 사용하지 않는 메모리를 회수합니다. 대부분의 Java 개발자는이 일시 정지를 자주 인식하지 못합니다. 보통 일시 정지가 짧고 매우 짧기 때문입니다. JVM이 많이 쌓이거나 더 제한적 일수록 이러한 일시 정지가 더 자주 발생합니다. VisualVM 과 같은 도구 를 사용하여이 프로세스를 시각화 할 수 있습니다 .

최신 버전의 Java에서는 가비지 수집 (GC) 알고리즘 을 조정할 수 있습니다 . 일반적으로 일시 정지하려는 시간이 짧을수록 가상 머신의 오버 헤드가 더 비쌉니다 (예 : GC 프로세스를 조정하는 데 소비 된 CPU 및 메모리).

언제 문제가 될까요? 밀리 초 미만의 일관된 응답 속도에 관심이있을 때마다 GC가 중요합니다. Java로 작성된 자동화 된 거래 시스템은 일시 정지를 최소화하기 위해 JVM을 크게 조정합니다. 그렇지 않으면 Java를 작성하는 회사는 항상 시스템의 응답 성이 높은 상황에서 C ++로 전환합니다.

기록을 위해, 나는 일반적으로 객체 회피를 용납 하지 않습니다 ! 기본적으로 객체 지향 프로그래밍입니다. GC가 방해가되는 경우에만이 방법을 조정 한 다음 더 짧은 시간 동안 일시 중지하도록 JVM을 조정하려고 시도한 후에 만 ​​조정하십시오. Java 성능 조정에 대한 좋은 책은 Charlie Hunt와 Binu John의 Java Performance 입니다.


10
대부분의 최신 JVM은 "세계 중지"보다 더 나은 가비지 수집 알고리즘을 지원합니다. 가비지 콜렉션에 소요 된 상각 시간은 malloc / free를 명시 적으로 호출하는 데 소요되는 시간보다 적은 경우가 많습니다. 또한 C ++ 메모리 관리는 별도의 스레드에서 실행됩니까?

10
Oracle의 최신 Java 버전은 이스케이프 분석을 수행 할 수 있습니다. 즉, 메소드를 이스케이프하지 않은 오브젝트는 스택에 할당되므로이를 자유롭게 정리할 수 있습니다. 메소드가 리턴되면 자동으로 할당이 해제됩니다.
Jesper

2
@ ThorbjørnRavnAndersen : 정말요? 당신은 정말 pause- 뜻 적은 GC, 또는 당신은 "일반적으로 병렬 -하지만 때로는-A-작은 비트 - 일시 중지"GC을 의미합니까? 나는 GC가 어떻게 프로그램을 멈추지 않고 동시에 객체들을 움직일 수 있는지 이해하지 못한다. 그것은 문자 그대로 나에게는 불가능 해 보인다.
Mehrdad

2
@ ThorbjørnRavnAndersen : 어떻게 "세상을 멈출"수 있지만 "JVM을 일시 정지"할 수 없습니까? 그건 말이되지 않습니다 ...
Mehrdad

2
@ ThorbjørnRavnAndersen : 아뇨. 나는 당신이 무슨 말을하는지 이해하지 못합니다. GC가 때때로 프로그램을 일시 정지하는 경우가 있는데,이 경우 정의에 따라 " 일시 정지 "되지 않거나 프로그램을 일시 정지 하지 않습니다 (따라서 "일시 정지 되지 않음"). GC가 작동하는 동안 프로그램이 일시 중지되었다는 것을 암시하는 것처럼 보이기 때문에 "계속 유지할 수 없을 때 세상을 멈 춥니 다"라는 문구에 해당합니다. 어떤 경우인지 (일시적인지 아닌지), 어떻게 가능한지 설명해 주시겠습니까?
Mehrdad


9

GC는 많은 단명 한 개체에 맞게 조정되었습니다.

즉, 객체 할당을 사소하게 줄일 수 있다면

하나의 예는 루프에서 문자열을 작성하는 것이며, 순진한 방법은

String str = "";
while(someCondition){
    //...
    str+= appendingString;
}

String+=작업 마다 새로운 객체 를 생성합니다 (그리고 a StringBuilder와 새로운 기본 char 배열)

이것을 다음으로 쉽게 다시 작성할 수 있습니다.

StringBuilder strB = new StringBuilder();
while(someCondition){
    //...
    strB.append(appendingString);
}
String str = strB.toString();

이 패턴 (불변의 결과와 로컬의 변이 가능한 중간 값)은 다른 것들에도 적용될 수 있습니다

그 외에는 유령을 쫓는 대신 실제 병목 현상을 찾기 위해 프로파일 러를 끌어 야합니다.


이의 가장 큰 장점 StringBuilder방법은입니다 사전 크기StringBuilder 그래서하는 결코 재 할당 와 기본 배열 StringBuilder(int)생성자를. 이를 통해 할당이 아닌 단일1+N 할당이됩니다.

2
@JarrodRoberson StringBuilder는 현재 용량을 적어도 두 배로 늘리거나, 즉 log (n) 할당에 대해서만 용량이 기하 급수적으로 증가 할 것입니다
ratchet freak

6

Joshua Bloch (Java 플랫폼 제작자 중 하나)는 2001 년 그의 책 Effective Java 에 썼습니다 .

풀의 오브젝트가 매우 무겁지 않은 경우 자체 오브젝트 풀을 유지하여 오브젝트 작성을 피하는 것은 좋지 않습니다. 객체 풀을 정당화하는 객체의 프로토 타입 예제는 데이터베이스 연결입니다. 연결 설정 비용이 충분히 높아서 이러한 오브젝트를 재사용하는 것이 합리적입니다. 그러나 일반적으로 자체 객체 풀을 유지 관리하면 코드가 복잡해지고 메모리 사용량이 증가하며 성능이 저하됩니다. 최신 JVM 구현에는 경량 객체에서 이러한 객체 풀을 쉽게 능가하는 최적화 된 가비지 수집기가 있습니다.


1
네트워크 연결과 같은 경우에도 중요한 것은 연결과 관련된 GC 할당 객체를 유지하는 것이 아니라 GC 관리 세계 외부에 존재하는 연결 세트를 유지하는 것입니다. 개체 자체를 풀링하는 것이 도움이 될 수있는 경우가 있습니다. 이러한 객체의 대부분은 동일한 객체에 대한 한 쌍의 참조가 의미는 있지만 동일하지만 구별되는 객체에 대한 한 쌍의 참조와 의미 적으로 동일 할 수 있지만 그럼에도 불구하고 몇 가지 장점이 있습니다. 예를 들어, 동일한 50 천 개의 문자열에 대한 두 개의 참조가 동일한 지 검사 할 수 있습니다.
supercat

2
... 길이가 다른 두 개의 고유하지만 동일한 문자열에 대한 참조보다 훨씬 빠릅니다.
supercat

5

이것은 실제로 특정 응용 프로그램에 따라 다르므로 일반적으로 말하기가 어렵습니다. 그러나 객체 생성이 실제로 응용 프로그램의 성능 병목 현상 인 경우 놀랍습니다. 속도가 느리더라도 코드 스타일의 이점은 아마도 성능을 능가합니다 (실제로 사용자에게 눈에 띄지 않는 한)

어쨌든, 추측하는 대신 실제 성능 병목 현상을 결정하기 위해 코드를 프로파일 링 할 때까지 이러한 것들에 대해 걱정하지 않아도됩니다. 그때까지는 성능이 아니라 코드 가독성을 위해 최선을 다해야합니다.


초기 버전의 Java에서는 가비지 콜렉터가 버려진 오브젝트를 정리할 때 상당한 비용이 발생했습니다. 최신 버전의 Java에서는 GC 옵션이 크게 향상되었으므로 객체 생성은 거의 문제가되지 않습니다. 웹 서버는 페이지로드의 일부로 응용 프로그램 서버에서 실제로 복잡한 것을 계산하지 않는 한 외부 시스템에 대한 IO 호출로 제한됩니다.
greg

3

동료가 불필요한 객체 생성의 관점에서 말한 것 같습니다. 동일한 객체를 자주 만드는 경우 해당 객체를 공유하는 것이 좋습니다. 객체 생성이 복잡하고 더 많은 메모리를 사용하는 경우에도 해당 객체를 복제하고 복잡한 객체 생성 프로세스를 만들지 않아도됩니다 (그러나 요구 사항에 따라 다름). 나는 "객체 생성이 비싸다"라는 문구를 맥락에서 취해야한다고 생각한다.

JVM 메모리 요구 사항과 관련하여 Java 8을 기다리면 -Xmx를 지정할 필요조차 없으며 메타 공간 설정이 JVM 메모리 요구를 처리하고 자동으로 커집니다.


사람들이 답을 투표하지 않고 의견을 남기면 매우 건설적인 일이 될 것입니다. 결국 우리 모두는 지식을 공유하기 위해 여기 있으며, 합당한 이유없이 판단을 전달하는 것은 어떤 목적에도 도움이되지 않습니다.
AKS

1
스택 교환에는 해당 답변에 의견이 게시 될 때 답변을 거절 한 사용자에게 알리는 메커니즘이 있어야합니다.
AKS

1

메모리를 할당하는 것보다 클래스를 만드는 것이 더 많습니다. 초기화도 있습니다. 왜 그 부분이 모든 답변에 포함되지 않는지 잘 모르겠습니다. 일반 클래스에는 일부 변수가 포함되어 있으며 초기화 형식을 수행하며 무료가 아닙니다. 클래스가 무엇인지에 따라 파일을 읽거나 다른 수의 느린 작업을 수행 할 수 있습니다.

따라서 클래스 생성자가 사용 가능한지 여부를 파악하기 전에 클래스 생성자가 수행하는 작업을 고려하십시오.


2
잘 설계된 클래스는 이러한 이유로 생성자에서 크게 들리지 않아야합니다. 예를 들어, 파일 읽기 클래스는 대상 파일이 시작시 존재하는지 확인하고 파일의 데이터가 필요한 첫 번째 메소드 호출까지 실제 파일 조작을 연기하여 인스턴스화 비용을 낮출 수 있습니다.
GordonM

2
추가 비용이 'if (firstTime)'으로 이동하면 루프에서 클래스를 다시 작성하는 것보다 클래스를 다시 사용하는 것보다 비용이 많이 듭니다.
Alex

비슷한 답변을 게시하려고했는데 이것이 정답이라고 생각합니다. 많은 사람들이 Java 객체를 만드는 것이 싸다는 것은 종종 생성 자나 추가 초기화가 싸지 않다는 것을 깨닫지 못한다는 말에 눈을 멀게합니다. 예를 들어 Swing의 ImageIcon 클래스는 미리로드 된 Image 객체를 전달하더라도 생성자가 상당히 비쌉니다. 그리고 @GordonM에 동의하지 않습니다 .JDK의 많은 클래스가 생성자에서 대부분의 초기화를 수행하므로 코드가 더 얇고 더 잘 설계됩니다.
qwertzguy

1

Java의 GC는 실제로 "버스트"방식으로 많은 객체를 빠르게 생성하는 측면에서 매우 최적화되어 있습니다. 내가 이해할 수있는 것에서 그들은 객체가 지속되는 경우에만 메모리 공간에 "버스트 사이클"의 종류에 대해 순차적 할당 기 (가변 크기 요청에 가장 빠르고 간단한 O (1) 할당 자)를 사용합니다. GC주기가 끝나면 GC가 하나씩 수집 할 수있는 곳으로 이동합니다.

그렇기 때문에 실제 사용자 엔드 요구 사항으로 측정 된 것처럼 성능 요구가 충분히 중요 해지면 객체에 오버 헤드가 발생하지만 생성 / 할당 측면에서는 그렇게 많이 생각하지 않습니다. 그것은 반사와 동적 파견 (같은 개념을 지원하기 위해 필요한 참조의 지역과 자바에있는 모든 개체의 추가 용량과 더 가지고 Float보다 큰 float의 정렬 요구 사항 64 비트에 더 큰 4 번 같은 일이 자주, 그리고를 배열이 Float반드시 내가 이해 한 것과 연속적으로 저장 되는 것은 아닙니다.)

필자가 Java에서 개발 한 것 중 가장 눈길을 끄는 것 중 하나는 내 필드 (VFX)의 헤비급 경쟁자가 인터랙티브 멀티 스레드 표준 경로 추적기 (방사선 캐싱 또는 BDPT 또는 MLS 또는 다른 것을 사용하지 않음)라고 생각하게 만들었습니다. CPU는 실시간 프리뷰를 제공하여 노이즈없는 이미지로 빠르게 수렴되었습니다. 나는 C ++의 전문가들과 함께 일하면서 어려움을 겪은 멋진 프로파일 러를 사용하여 경력을 쌓았습니다.

그러나 나는 소스 코드를 들여다 보았고 사소한 비용으로 많은 객체를 사용했지만 경로 추적기 (BVH 및 삼각형 및 재료)의 가장 중요한 부분은 객체를 매우 명확하고 고의로 피할 수 없었습니다. 주로 float[]int[])를 사용하여 훨씬 적은 메모리를 사용하고 공간적 위치를 보장 float하여 배열 에서 하나 에서 다음으로 이동했습니다. 저자가 박스형을 사용했다면Float거기에는 성능에 다소 큰 비용이 듭니다. 그러나 우리는 그 엔진에서 가장 절대적으로 중요한 부분을 이야기하고 있으며, 개발자가 얼마나 능숙하게 최적화했는지를 감안할 때, 그는 다른 곳에서 객체를 행복하게 사용했기 때문에 그 측정을 최적화하고 매우 신중하게 적용했습니다. 그의 인상적인 실시간 경로 추적기에 사소한 비용.

동료에게 Java 객체 생성에서 수행 할 수있는 가장 비싼 작업이라고 들었습니다. 따라서 가능한 한 적은 수의 객체를 만드는 것으로 결론을 내릴 수 있습니다.

나만큼 성능이 중요하지 않은 분야에서도 중요하지 않은 장소에 자신을 햄스트링하면 효율적인 제품을 쓰지 않을 것입니다. 가장 성능이 중요한 분야는 생산성에 대한 요구가 더 높아질 수 있다고 주장합니다. 왜냐하면 우리는 그렇지 않은 일에 시간을 낭비하지 않고 정말로 중요한 핫스팟을 조정할 수있는 여분의 시간이 필요하기 때문입니다. . 위의 경로 추적기 예제와 마찬가지로 저자는 이러한 최적화를 능숙하고 신중하게 측정 한 후에 진정으로 진정으로 중요하고 아마도 후 시점에있는 곳에만 적용하고 다른 곳에서도 여전히 행복하게 사용하는 객체에만 적용했습니다.


1
첫 번째 단락이 제대로 진행되고 있습니다. 에덴과 젊은 공간은 약 1 개의 복사 수집기를 사용합니다. 죽은 물건에 대한 0 비용. 나는 이 프리젠 테이션을 강력히 추천 한다 . 참고로, 당신은이 질문이 2012 년의 것이라는 것을 알고 있습니다.
JimmyJames

@JimmyJames 나는 지루해하고 오래된 질문을 포함하여 질문을 통해 선별하고 싶습니다. 사람들이 내 괴사를 신경 쓰지 않기를 바랍니다! :-D
Dragon Energy

@JimmyJames 더 이상 박스 유형에 추가 메모리 요구 사항이 있고 배열에서 연속적이라고 보장되지 않습니까? 나는 객체가 자바 저렴한 먼지 생각하는 경향이 있지만, 상대적으로 비싼 수있는 하나의 경우처럼 float[]Float[]전자 순차적으로 백만을 처리하는 것은 상대적으로 매우 빠르게 두 번째보다 더 수 있습니다.
드래곤 에너지

1
처음 여기에 게시를 시작했을 때도 마찬가지였습니다. 오래된 질문에 대한 대답이 거의 관심을 기울이지 않을 때 놀라지 마십시오.
JimmyJames

1
박스형은 프리미티브보다 더 많은 공간을 사용한다고 가정합니다. 그 주변에 잠재적으로 최적화가 있지만 일반적으로 설명하는 것처럼 생각합니다. Gil Tene (위의 프레젠테이션)은 구조체의 이점을 제공하지만 여전히 객체를 사용하는 특별한 종류의 컬렉션을 추가하라는 제안에 대해 또 다른 이야기를했습니다. 흥미로운 아이디어입니다 .JSR의 상태를 잘 모르겠습니다. 비용은 주로 당신이 암시하는 시간 때문입니다. 객체가 '탈출'되는 것을 피할 수 있다면 스택 할당이 가능하고 힙을 건드리지 않을 수도 있습니다.
JimmyJames

0

사람들이 자바에서 객체 생성은 큰 비용이 아니라고 말했지만 (추가 등과 같은 대부분의 간단한 작업보다 더 큽니다) 너무 피해서는 안됩니다.

그것은 여전히 ​​비용이 든다고 말하고 때로는 가능한 많은 물건을 긁어 내려고 할 수도 있습니다. 그러나 프로파일 링 후에 만 ​​이것이 문제라는 것을 보여주었습니다.

다음은 주제에 대한 훌륭한 프레젠테이션입니다. https://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf


0

나는 이것에 대해 빠른 마이크로 벤치 마크 를 했고 github에 전체 소스 를 제공 했습니다. 필자의 결론은 객체를 만드는 것이 비싸거나 그렇지 않은 것이 문제가 아니라 GC가 처리해야 할 개념으로 객체를 지속적으로 만드는 것이 응용 프로그램이 GC 프로세스를 더 빨리 트리거하게한다는 것입니다. GC는 비용이 많이 드는 프로세스이므로 가능할 때마다 피하고 밀어 내려고하지 않는 것이 가장 좋습니다.


이것은 이전 15 답변에서 제시되고 설명 된 점에 비해 실질적인 것을 제공하지 않는 것 같습니다. 2 년 전에 질문을
받았으며
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.