Java의 부울 기본 크기가 정의되지 않은 이유는 무엇입니까?


111

Java 가상 머신 사양 부울 제한적으로 지원이 있음을 말한다 원시 유형.

부울 값에 대한 조작 전용 Java 가상 머신 명령은 없습니다. 대신 부울 값에 대해 작동하는 Java 프로그래밍 언어의 표현식은 Java 가상 머신 int 데이터 유형의 값을 사용하도록 컴파일됩니다.

위의 내용은 부울에서 작동 할 때 int 데이터 유형이 사용되지만 32 비트 메모리 구성이라는 것을 암시합니다 (잘못 해석했을 수 있음). 부울은 1 비트의 정보 만 나타냅니다.

  • 바이트 또는 짧은 유형이 int 대신 부울에 대한 프록시로 사용되지 않는 이유는 무엇입니까?
  • 주어진 JVM에 대해 부울 유형을 저장하는 데 정확히 얼마나 많은 메모리가 사용되는지 알아내는 가장 안정적인 방법은 무엇입니까?

답변:


116

짧은 대답 : 예, 부울 값은 32 비트 엔터티로 조작되지만 부울 배열은 요소 당 1 바이트를 사용합니다.

더 긴 답변 : JVM은 로컬 변수, 메소드 인수 및 표현식 값을 보유하는 데 사용되는 32 비트 스택 셀을 사용합니다. 1 셀보다 작은 프리미티브는 패딩되고 32 비트 (long 및 double)보다 큰 프리미티브는 2 셀을 사용합니다. 이 기술은 opcode의 수를 최소화하지만 몇 가지 특이한 부작용 (예 : 바이트 마스킹 필요)이 있습니다.

배열에 저장된 프리미티브는 32 비트 미만을 사용할 수 있으며 배열에서 프리미티브 값을로드하고 저장하는 데 서로 다른 opcode가 있습니다. 부울 및 바이트 값은 모두 baloadbastoreopcode를 사용하며 이는 부울 배열이 요소 당 1 바이트를 사용함 을 의미합니다.

메모리 내 개체 레이아웃에 관한 한, 이것은 "비공개 구현" 규칙에 따라 다룹니다 . 1 비트, 1 바이트 또는 다른 포스터에서 언급했듯이 64 비트 더블 워드 경계에 정렬 될 수 있습니다. 대부분의 경우 기본 하드웨어의 기본 워드 크기 (32 비트 또는 64 비트)를 사용합니다.


부울이 사용하는 공간의 양을 최소화하는 한 : 대부분의 응용 프로그램에서는 실제로 문제가되지 않습니다. 스택 프레임 (지역 변수 및 메서드 인수 포함)은 그다지 크지 않으며 큰 체계에서 객체의 이산 부울도 그다지 크지 않습니다. 부울이 많은 객체가 많은 경우 getter 및 setter를 통해 관리되는 비트 필드를 사용할 수 있습니다. 그러나 메모리의 패널티보다 더 큰 CPU 시간의 패널티를 지불하게됩니다.


부울 / 바이트 클래스 멤버의 경우에도 4 바이트라는 것이 사실입니까? 클래스 인스턴스는 스택에 전체적으로 할당되므로 JVM은 아마도 부울 / 바이트 멤버 당 1 바이트를 사용하고 마지막으로 전체 클래스 인스턴스에 대해 4 바이트 정렬을 만들어야합니다. 그렇습니까? (당신이 이것을 증명하는 참조가 있다면, 공유하십시오)
dma_k

@dma_k : 내 응답에서 언급했듯이 클래스 인스턴스의 레이아웃은 구현에 따라 다릅니다. 그러나 클래스 인스턴스는 스택에 저장되지 않고 힙에 저장됩니다 (스택에서 힙으로 객체를 이동하는 JDK 7 "이스케이프 분석"에 대한 일부 참조를 볼 수는 있지만 그렇지 않은 것 같습니다. java.sun.com/javase/7/docs/technotes/guides/vm/… 참조)
kdgregory

1
때로는 부울을 패킹하는 것이 실제로 더 빠를 수 있습니다. 캐시 크기가 중요 할 때마다 물건을 포장하는 것이 좋습니다. 예를 들어, 분할 된 프라임 시브는 32kB (L1 캐시 크기)의 청크에서 작동하는 것이 분할되지 않은 시브보다 훨씬 빠릅니다. 청크 사이에 약간의 오버 헤드가 있으며 패킹을 사용하면 오버 헤드를 8 배 더 적게 지불합니다. 아직 측정하지 않았습니다.
maaartinus

7

상속 계층의 어딘가에 단일 부울은 최대 8 바이트를 사용할 수 있습니다! 이것은 패딩 때문입니다. 자세한 내용은 Java 개체에서 사용하는 메모리 양을 참조하십시오 . :

부울이 소비하는 양에 대한 질문으로 돌아가서, 예, 적어도 1 바이트를 소비하지만 정렬 규칙으로 인해 훨씬 ​​더 많이 소비 할 수 있습니다. IMHO boolean []이 항목 당 1 바이트가 아닌 1 비트를 소비하고 정렬 및 배열의 ​​크기 필드로 인해 약간의 오버 헤드가 발생한다는 사실을 아는 것이 더 흥미 롭습니다. 큰 비트 필드가 유용한 그래프 알고리즘이 있으며, boolean []을 사용하는 경우 실제로 필요한 것보다 거의 정확히 8 배 더 많은 메모리가 필요합니다 (1 바이트 대 1 비트).


어쨌든 부울 []을 어떻게 사용합니까?
Thomas Jung

boolean []을 마스크로 사용할 수 있습니다. 유용한 방법이 있기 때문에 때때로 BitSet이 더 나을 수 있습니다.
Michael Munsey

5

5th Edition of Java in a Nutshell (O'Reilly)에서는 부울 기본 유형이 1 바이트라고 말합니다. 힙 검사 결과에 따라 잘못된 것일 수 있습니다. 대부분의 JVM이 변수에 1 바이트 미만을 할당하는 데 문제가 있는지 궁금합니다.


3

부울 매핑은 32 비트 CPU를 염두에두고 수행되었습니다. int 값은 32 비트이므로 한 번의 작업으로 처리 할 수 ​​있습니다.

다음은 Peter Norvig의 Java IAQ : Infrequently Answered Questions 에서 크기를 측정하기 위한 솔루션입니다 (일부 부정확 함).

static Runtime runtime = Runtime.getRuntime();
...
long start, end;
Object obj;
runtime.gc();
start = runtime.freememory();
obj = new Object(); // Or whatever you want to look at
end =  runtime.freememory();
System.out.println("That took " + (start-end) + " bytes.");

이 대화는 기본 요소에 대한 것이므로 기본 요소가 인스턴스 또는 배열의 필드가 아닌 경우 힙에 저장되지 않으므로이를 테스트하는 데 창의적이어야합니다. 그리고 이들 중 어느 것도 Java가 어쨌든 스택에 저장하도록 선택하는 방법에 대한 질문에 대답하지 않습니다.
Jesse

2

CPU는 특정 데이터 유형 길이에서 작동합니다. 32 비트 CPU의 경우 32 비트 길이이므로 Java에서 'int'라고 부릅니다. CPU가 처리하기 전에 아래 또는 위의 모든 항목을이 길이로 채우거나 분할해야합니다. 시간이 많이 걸리지는 않지만 기본 작업에 1 개 대신 2 개의 CPU주기가 필요한 경우 비용 / 시간이 두 배가됩니다.

이 사양은 32 비트 CPU 전용이므로 기본 데이터 유형으로 부울을 처리 할 수 ​​있습니다.

여기에는 속도 또는 메모리 중 하나만있을 수 있습니다. SUN은 속도를 결정했습니다.


1

부울은 정보의 한 비트를 나타내지 만 "크기"는 정확하게 정의 된 것이 아닙니다. Sun Java 자습서는 말합니다. 부울 리터럴에는 true와 false의 두 가지 가능한 값만 있습니다. 자세한 내용은 Java 데이터 유형 을 참조하십시오.


-10

다음과 같이 하나의 .java 파일을 만드는 것은 어떨까요?

Empty.java

class Empty{
}

다음과 같은 클래스 :

NotEmpty.java

class NotEmpty{
   boolean b;
}

둘 다 컴파일하고 .class 파일을 16 진 편집기와 비교하십시오.


5
이것은 메모리에서 기본 부울 유형의 크기를 조정하는 것과 관련이없는 또 다른 메트릭입니다.
Joel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.