Java에서 객체 생성을 피해야합니까? 결론을 내릴

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

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



답변

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

가장 비싼 작업은 듣고 있습니다 . 그들은 당신에게 시간을 낭비하고 (이 답변이 게시 된 날짜 기준으로) 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를 능가하고 있습니다.


답변

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

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

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


답변

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

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


답변

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

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

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

답변

동료의 말에 진실의 핵심이 있습니다. 나는 객체 생성 문제 가 실제로 가비지 수집 이라는 것을 정중하게 제안한다 . 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 입니다.


답변

오버 헤드로 인해 Java에서 너무 많은 오브젝트를 작성하지 않는 경우가 있습니다
. Android 플랫폼의 성능을 위해 설계되었습니다.

그 외에는 위의 답변이 사실입니다.


답변

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

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

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

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

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

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

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

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

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