메모리 사용 분석 : Java 대 C ++ 무시할 수 있습니까?


9

Java로 작성된 정수 객체의 메모리 사용량은 C ++로 작성된 정수 객체의 메모리 사용량과 어떻게 비교됩니까? 그 차이는 무시할 만합니까? 차이 없음? 큰 차이? int는 언어에 관계없이 int이기 때문에 동일한 것으로 추측합니다 (?)

내가 묻는 이유 는 프로그램의 메모리 요구 사항이 프로그래머가 주어진 문제를 해결하지 못할 때를 아는 것의 중요성에 대해 읽었 기 때문 입니다.

나를 매료시킨 것은 단일 Java 객체를 만드는 데 필요한 메모리 양입니다. 예를 들어 정수 객체를 생각해보십시오. 내가 틀렸지 만 Java 정수 객체에 24 바이트의 메모리가 필요한 경우 수정하십시오.

  • int 인스턴스 변수의 경우 4 바이트
  • 16 바이트의 오버 헤드 (객체 클래스, 가비지 수집 정보 및 동기화 정보 참조)
  • 4 바이트의 패딩

다른 예로, 객체로 구현 된 Java 배열에는 48 바이트 이상이 필요합니다.

  • 헤더 정보 24 바이트
  • 16 바이트의 객체 오버 헤드
  • 길이는 4 바이트
  • 패딩을위한 4 바이트
  • 더하기 값을 저장하는 데 필요한 메모리

이러한 메모리 사용량은 C ++로 작성된 동일한 코드와 어떻게 비교됩니까?

필자는 필자가 작성한 C ++ 및 Java 프로그램의 메모리 사용에 대해 잘 모르지만 알고리즘에 대해 배우기 시작하면서 컴퓨터 리소스에 대한 인식이 높아지고 있습니다.


6
C ++에서 "정수 객체"란 무엇입니까? int? 그렇다면 C ++ int가 32 비트 인 한 intJava와 비교해야합니다 Integer.
Mat

+1 int 변수가 하나 뿐인 c ++ 클래스를 만든 경우 인스턴스화
Anthony

3
int는 int가 아닙니다-플랫폼에 따라 다릅니다

1
int 멤버가 하나만있는 C ++에는 일반적으로 오버 헤드가 없습니다. 플랫폼이 int (일반적으로 현재 PC 플랫폼에서 4 바이트)를 저장하는 데 사용하는만큼의 공간을 사용합니다.
Dirk Holsopple

메모리에 대해 궁금한 Java 프로그래머의 경우 +1 무엇보다도 메모리 인식은 현대 건축에서 성능을 결정하는 가장 중요한 요소입니다.
imallett

답변:


15

플랫폼과 구현에 따라 다릅니다.

C ++는 크기 char가 정확히 1 바이트이고 너비가 8 비트 이상 임을 보장합니다 . 그리고, a의 크기는 short int16 비트 이상이고보다 작지 않다 char. 의 크기는의 크기 int만큼 큽니다 short int. 의 크기는 long int32 비트 이상이고 int보다 작지 않습니다.

sizeof(char) == 1; sizeof(long int) >= sizeof(int) >= sizeof(short int) >= sizeof(bool) >= sizeof(char).

C ++의 실제 메모리 모델은 매우 작고 예측 가능 합니다. 예를 들어 객체, 배열 또는 포인터에 메타 데이터가 없습니다. 구조체와 클래스는 배열처럼 연속적이지만 필요에 따라 필요한 곳에 패딩을 배치 할 수 있습니다.

솔직히 말해서 Java 메모리 사용량은 실행되는 코드보다 Java 구현에 더 의존하기 때문에 그러한 비교는 어리석은 일입니다.


1
사실이지만 비교를 위해 동등한 크기의 정수 유형을 사용해야한다고 말합니다 (다른 이름으로 만 사용할 수있는 경우에도). 결국, 다른 크기는 다른 의미를 의미하며, (일부는 아님) 많은 공통 플랫폼에서 크기가 동일하거나 같은 크기의 정수를 다른 이름으로 사용할 수 있습니다.

OP에 대한 참고 사항 : 정수의 크기를 선택하는 것이 좋습니다 int32_t. C ++에서 32 비트 int를 원한다면을 사용할 수 있습니다 .
K.Steff

9

대부분의 답변은 상당히 중요한 몇 가지 사항을 무시하는 것 같습니다.

첫째, 엄청나게 많은 Java에서 int거의 원시를 보지 못합니다. 거의 모든 사용은의 것입니다 Integer. 따라서 C 또는 C ++에서와 거의int 같은 크기 일 수 있다는 사실 은 ( 내 경험상, 대신에 만 사용 하는 코드의 작은 비율 .intintInteger

둘째, 개별 객체의 크기는 프로그램의 전체 메모리 공간과 거의 관련이 없습니다. Java에서 프로그램의 메모리 사용량은 주로 가비지 수집기가 조정 된 방법과 관련이 있습니다. 대부분의 경우, GC는 속도를 최대화하도록 조정되며, GC를 최대한 자주 실행하는 것을 의미합니다.

현재로서는 편리한 링크가 없지만 Java가 C와 동일한 속도로 실행할 수 있음을 보여주는 몇 가지 테스트가 있었지만 그렇게하려면 GC를 거의 7 번 정도 사용할 정도로 거의 실행하지 않아야합니다. 기억. 개별 객체의 크기가 7 배나 크지 않기 때문에 너무 자주 수행하면 GC가 꽤 비쌀 수 있기 때문입니다. 더 나쁜 것은 GC는 단순히 객체 사용이 끝났다는 것을 알기보다는 더 이상 객체에 액세스 할 수있는 방법이 없다는 것을 "증명"할 수있을 때만 메모리를 해제 할 수 있다는 것입니다. 즉, 메모리 사용을 최소화하기 위해 GC를 더 자주 실행하더라도 메모리 사용량이 큰 프로그램을 계획 할 수 있습니다. 이와 같은 경우에는 7 대신 2 또는 3으로 요소를 줄일 수 있습니다.1 .

상황에 따라 중요하지 않을 수도있는 또 다른 요인이 있습니다. JVM 자체가 차지하는 메모리입니다. 이것은 다소 고정되어 있으므로 앱이 자체 스토리지를 많이 필요로하지 않으면 백분율이 크거나 앱이 많이 저장 해야하는 경우에는 소극적 일 수 있습니다. 적어도 내 컴퓨터에서 가장 사소한 Java 응용 프로그램조차도 20-25MB와 같은 것을 차지하는 것 같습니다 (사소한 프로그램의 경우 1000x 이상이거나 큰 경우에는 거의 작을 수 있음).


1 아무도 C ++로 얻을 수있는 것에 가까운 풋 프린트로 Java를 작성할 수 있다고 말할 수는 없습니다. 이 말을 단지의 단지 객체의 같은 수의 / 크기를 가진, 그리고 당신이 원칙적으로받지 않습니다 정말 자주 GC를 실행.


7
첫 번째 점에 대해서는 : 난 더 자바 사람이 아니지만, 자바 API를 내가 사용한 적이 보았다 Integer(왜 그들이 것?) 대신 int. Integer형식 소거로 인해 일반 컬렉션 만 사용할 수는 없지만 , 관심이 있다면 int필요한 기본 형식이나 다른 기본 형식으로 대체 할 수 있습니다. 그리고 일반적인 래핑 코드를 통과하는 임시 권투가 있습니다 (예 :) Object[]. 그 외에도 GC 공간 오버 헤드에 대한 소스가 있습니까? 나는 그것을 의심하지 않고 단지 호기심이 있습니다.


9

이 모든 것이 Java 및 C ++ 모두에 대해 깊이 구현 정의되어 있음을 알고 싶습니다. 즉, Java의 객체 모델에는 약간의 공간이 필요합니다.

C ++ 객체는하지 (일반적으로) 필요한 모든 구성원이 필요로하는 것을 제외하고 저장합니다. (사용자 정의 모든 것이 참조 유형 인 Java와 달리) 클라이언트 코드는 값 유형 또는 참조 유형으로 객체를 사용할 수 있습니다. 즉, 객체는 다른 객체에 대한 포인터 / 참조를 저장하거나 객체를 직접 저장할 수 있습니다. 간접적으로. virtual메소드 가있는 경우 객체 당 하나의 추가 포인터가 필요 하지만 다형성없이 처리 할 수있는 유용한 클래스가 상당히 많으며이를 필요로하지 않습니다. GC 메타 데이터와 객체 별 잠금이 없습니다. 따라서 class IntWrapper { int x; public: IntWrapper(int); ... };객체는 일반 공간보다 더 많은 공간을 필요로하지 않으며 int컬렉션 및 기타 객체에 직접 (즉, 간접적으로) 배치 할 수 있습니다.

C ++의 Java 배열과 동등한 사전 제작이 없으므로 배열은 까다로워집니다. new[]오버 헤드 / 메타 데이터가없는 객체를 단순히 할당 할 수는 있지만 길이 필드는 없습니다. 구현은 아마도 하나를 저장하지만 액세스 할 수는 없습니다. std::vector동적 배열이므로 추가 오버 헤드와 더 큰 인터페이스가 있습니다. std::array및 C 스타일 배열 (int arr[N];), 컴파일 타임 상수가 필요합니다. 이론 상으로는 객체의 저장 공간과 길이에 대한 단일 정수가되어야합니다. 그러나 공간을 거의 차지하지 않으면 서 동적 크기 조정과 완전한 기능을 갖춘 인터페이스를 얻을 수 있기 때문에 실제로 사용하면됩니다. 이러한 컬렉션과 다른 모든 컬렉션은 기본적으로 개체를 값으로 저장하므로 간접 참조 및 참조 공간을 절약하고 캐시 동작을 향상시킵니다. 간접적으로 얻으려면 포인터를 명시 적으로 저장해야합니다 (스마트 포인터).

이러한 비용 절감 중 일부는 Java에 포함 된 기능을 포함하지 않아서 제공되며 C ++에 해당하는 것이 Java에 해당하는 것 (*)보다 덜 최적화되기 때문에 위의 비교는 전적으로 공평하지 않습니다. 일반적인 방법은 구현 virtual정확하게 구현하는 일반적인 방법으로 많은 오버 헤드로 C ++을 강요하며에서 virtual자바. 잠금을 얻으려면 완전한 기능을 갖춘 mutex 객체가 필요합니다.이 객체는 아마도 몇 비트보다 큽니다. (참조 카운트를 얻으려면 하지GC와 동일하며 사용해서는 안되지만 때로는 유용해야 함) 참조 카운트 필드를 추가하는 스마트 포인터가 필요합니다. 개체를 신중하게 구성하지 않으면 참조 수, 스마트 포인터 개체 및 참조 개체가 완전히 별도의 위치에 있으며, 올바르게 구성하더라도 공유 포인터는 여전히 하나가 아니라 두 개의 포인터 일 수 있습니다. 다시 말하지만, 좋은 C ++ 스타일은 이러한 기능을 충분히 사용하지 않으므로 실제로 작성된 C ++ 라이브러리의 객체는 더 적게 사용합니다. 이것이 반드시 전체 메모리 사용량을 의미 하지는 않지만 C ++이 이와 관련하여 좋은 출발을 의미합니다.

(*) 예를 들어, 유형 정보를 다양한 플래그와 병합하고 객체에 대한 잠금 비트를 제거하여 가상 통화, ID 해시 코드 및 일부 객체에 대해 한 단어로만 잠금 (및 다른 많은 객체에 대해 두 단어로)을 얻을 수 있습니다. 자물쇠가 필요할 것 같지 않습니다. 참조 자바 객체 모델의 공간 - 및 시간 효율적인 구현 이 다른 최적화에 대한 자세한 설명은 데이비드 F. 베이컨, 스티븐 J. 핑크, 데이비드 로브로 (PDF)를.


3

intJava에서 일반 int은 C ++에서와 동일한 공간을 차지 하지만 두 구현 모두 동일한 정수 크기와 메모리 정렬을 사용합니다.

int 'object'( 상자 형 정수, 즉 Integer클래스의 인스턴스)는 Java에서 클래스 인스턴스의 모든 오버 헤드를 전달하므로 intC ++ 보다 훨씬 큽니다 . 그러나 C ++의 객체에 Java 객체와 기본적으로 제공되는 기능 (다형성, 복싱, 가비지 수집, RTTI)과 동일한 기능을 갖춘 경우 아마도 동일한 객체로 끝날 것입니다 크기.

그리고 최적화 고려 사항이 있습니다. 실행 모델과 프로그래밍 패러다임이 다르기 때문에 사소한 문제가 두 언어 모두에서 동일하게 해결되지는 않을 것이므로이 수준에서 스토리지 크기를 비교하는 것은별로 의미가 없습니다.

그렇습니다. Java 객체는 기본적으로 C ++ 클래스보다 오버 헤드가 많지만 더 많은 기능이 제공되므로 프로그래밍 스타일이 달라져 좋은 프로그래머가 두 언어의 장점과 단점을 모두 활용할 수 있습니다.


+1 더 많은 오버 헤드가 있지만 Java의 더 많은 기능, 이제 이해합니다.
Anthony
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.