ขนาดของตัวแปรบูลีนใน Java คืออะไร?


89

ใครสามารถบอกขนาดบิตของบูลีนใน Java ได้หรือไม่?


1
ถามเหมือนกันที่นี่: stackoverflow.com/questions/1907318/…
dma_k

คำตอบ:


41

มันขึ้นอยู่กับเครื่องเสมือน


9
ต้องการชี้ไปที่เอกสารหรือไม่? ฉันคิดว่ามันยากที่จะเชื่อว่าขนาดของบูลีนขึ้นอยู่กับเครื่อง นั่นหมายความว่าการแทนค่าไบนารีของคลาสที่มีบูลีนจะมีขนาด (และเลย์เอาต์หน่วยความจำ) ที่แตกต่างกันใน VM ที่แตกต่างกันและนั่นหมายความว่า VM จะเข้ากันไม่ได้
David Rodríguez - น้ำลายไหล

14
ฉันคิดว่าเป็นนัยว่าคำถามนั้นอ้างถึงขนาดของตัวแปรบูลีนในหน่วยความจำไม่ใช่ขนาดของตัวแปรบูลีนที่เข้ารหัสในไฟล์คลาส ขนาดในหน่วยความจำจะแตกต่างกันไปตาม VM ตามเอกสารของ Sun ขนาดในไฟล์คลาสจะคงที่
William Brendel

3
@ DavidRodríguez-dribeas - Sun JVM ในช่วงเวลาของ Java 1.1 ใช้ 4 ไบต์สำหรับบูลีนเมื่อเก็บเป็นอินสแตนซ์หรือตัวแปรอัตโนมัติ สิ่งนี้ทำให้การใช้งานตัวแปล bytecode ง่ายขึ้น (ซึ่งถือว่าบูลใช้พื้นที่ 4 ไบต์บนสแตก) และเป็นเส้นทางที่มีความต้านทานน้อยที่สุด เมื่อเราใช้ iSeries "Classic" JVM เราพบวิธีสร้างอินสแตนซ์ vars 1 ไบต์เนื่องจากช่วยเพิ่มความกะทัดรัดของวัตถุบางอย่างได้อย่างมาก (ซึ่งมีผลกระทบอย่างมากต่อประสิทธิภาพ) เห็นได้ชัดว่าจากโพสต์ด้านล่างนักพัฒนา Sun / Oracle ได้คิดหาวิธีทำเช่นเดียวกันในเวอร์ชันที่ใหม่กว่า
Hot Licks

แต่ถูกต้องเมื่อปลายปี 2017 JavaDocsกล่าวว่า: boolean: The boolean data type... This data type represents one bit of information, but its "size" isn't something that's precisely defined- แต่ประเด็นของคุณถูกต้องสามารถใช้ลิงก์และข้อมูลที่ดีกว่าได้ :)
JimLohse

185

ขึ้นอยู่กับเครื่องเสมือน แต่ง่ายต่อการปรับรหัสจากคำถามที่คล้ายกันซึ่งถามเกี่ยวกับไบต์ใน Java :

class LotsOfBooleans
{
    boolean a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af;
    boolean b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf;
    boolean c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf;
    boolean d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df;
    boolean e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef;
}

class LotsOfInts
{
    int a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af;
    int b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf;
    int c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf;
    int d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df;
    int e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef;
}


public class Test
{
    private static final int SIZE = 1000000;

    public static void main(String[] args) throws Exception
    {        
        LotsOfBooleans[] first = new LotsOfBooleans[SIZE];
        LotsOfInts[] second = new LotsOfInts[SIZE];

        System.gc();
        long startMem = getMemory();

        for (int i=0; i < SIZE; i++)
        {
            first[i] = new LotsOfBooleans();
        }

        System.gc();
        long endMem = getMemory();

        System.out.println ("Size for LotsOfBooleans: " + (endMem-startMem));
        System.out.println ("Average size: " + ((endMem-startMem) / ((double)SIZE)));

        System.gc();
        startMem = getMemory();
        for (int i=0; i < SIZE; i++)
        {
            second[i] = new LotsOfInts();
        }
        System.gc();
        endMem = getMemory();

        System.out.println ("Size for LotsOfInts: " + (endMem-startMem));
        System.out.println ("Average size: " + ((endMem-startMem) / ((double)SIZE)));

        // Make sure nothing gets collected
        long total = 0;
        for (int i=0; i < SIZE; i++)
        {
            total += (first[i].a0 ? 1 : 0) + second[i].a0;
        }
        System.out.println(total);
    }

    private static long getMemory()
    {
        Runtime runtime = Runtime.getRuntime();
        return runtime.totalMemory() - runtime.freeMemory();
    }
}

เพื่อย้ำอีกครั้งว่านี่ขึ้นอยู่กับ VM แต่บนแล็ปท็อป Windows ของฉันที่ใช้ JDK build 1.6.0_11 ของ Sun ฉันได้ผลลัพธ์ต่อไปนี้:

Size for LotsOfBooleans: 87978576
Average size: 87.978576
Size for LotsOfInts: 328000000
Average size: 328.0

นั่นแสดงให้เห็นว่าโดยพื้นฐานแล้วบูลีนสามารถบรรจุเป็นไบต์ได้โดย Sun's JVM


21
@skeet - ขอคารวะคุณจริงๆคำตอบของคุณยอดเยี่ยมมาก
Warrior

2
@warrior: ในขณะที่ฉันได้รับรหัสสำหรับ "ไบต์" แล้วการเปลี่ยนเป็น "บูลีน" ก็ค่อนข้างตรงไปตรงมา :)
Jon Skeet

3
System.gc () ไม่รับประกันการทำความสะอาดหน่วยความจำ เพียงแค่สั่งให้ JVM รันการรวบรวมขยะ แต่ไม่ได้หมายความว่าผู้รวบรวมจะทำความสะอาดบางสิ่งบางอย่างจริงๆ จำไว้ว่านักสะสมทำความสะอาดวัตถุที่ไม่ได้ใช้ อ็อบเจ็กต์จะไม่ถูกใช้หากโปรแกรมไม่มีการอ้างอิงอีกต่อไป ดังนั้นในการทดสอบของคุณฉันจะทิ้งการอ้างอิงอย่างชัดเจนโดยตั้งค่า LotsOfBooleans เป็น null ก่อนที่จะเรียกใช้ gc (); หรือเพียงแค่รันหลักครั้งเดียวด้วยบูลีนหนึ่งครั้งด้วย int จากนั้นเปรียบเทียบตัวเลข
Randa Sbeity

2
@RandaSbeity หรือดีกว่า: ตรวจสอบให้แน่ใจว่าคุณเก็บข้อมูลอ้างอิงทั้งสองและคำนวณความแตกต่างของหน่วยความจำ ซึ่งเป็นสิ่งที่เกิดขึ้นที่นี่
biziclop

1
มีคำถามใดบ้างที่ Jon Skeet ไม่สามารถตอบได้?
Andreas Hartmann

31

ข้อมูลจริงที่แสดงโดยค่าบูลีนใน Java คือ 1 บิต: 1 สำหรับจริง 0 สำหรับเท็จ อย่างไรก็ตามขนาดจริงของตัวแปรบูลีนในหน่วยความจำไม่ได้กำหนดไว้อย่างแม่นยำโดยข้อกำหนด Java ดูชนิดข้อมูลดั้งเดิมในชวา

ชนิดข้อมูลบูลีนมีค่าที่เป็นไปได้เพียงสองค่าเท่านั้น: จริงและเท็จ ใช้ชนิดข้อมูลนี้สำหรับแฟล็กธรรมดาที่ติดตามเงื่อนไขจริง / เท็จ ประเภทข้อมูลนี้แสดงถึงข้อมูลเพียงเล็กน้อย แต่ "ขนาด" ไม่ใช่สิ่งที่กำหนดไว้อย่างชัดเจน


21

หมายเหตุด้าน ...

หากคุณกำลังคิดที่จะใช้อาร์เรย์ของวัตถุบูลีนอย่าทำ ใช้ BitSet แทน - มีการเพิ่มประสิทธิภาพบางอย่าง (และวิธีการพิเศษที่ดีช่วยให้คุณได้รับชุด / ไม่ตั้งค่าบิตถัดไป)


นี่ไม่ใช่เรื่องจริงเสมอไปstackoverflow.com/questions/605226/…
Przemek

คำตอบดังกล่าวแสดงให้เห็นว่ามีเหตุผลสำคัญในการใช้บูลีน [] แต่ตามความคิดเห็นในนั้นระบุว่าไม่มีอะไรให้สำรองมากนัก ต้องบอกว่า: ฉันไม่ได้เขียนโปรแกรมใน Java มากนัก (และไม่ได้ให้หลักฐานใด ๆ ด้วย)
Matthew Schinckel

6

ฉันอ่านว่า Java สงวนไว้หนึ่งไบต์สำหรับbooleanประเภทข้อมูล แต่ใช้เพียงบิตเดียว แต่เอกสารที่บอกว่าขนาด "ของมัน '' ไม่ได้เป็นสิ่งที่กำหนดไว้อย่างแม่นยำ" ดูที่นี่.


นั่นคือบทช่วยสอนไม่ใช่ "เอกสารประกอบ" เอกสารประกอบคือ JLS, JVM Spec. และ Javadoc
user207421

2

booleanค่ารวบรวมintชนิดของข้อมูลใน JVM ดูที่นี่ .


2
นั่นไม่จำเป็นต้องเก็บไว้ในหน่วยความจำเสมอไปและฉันคิดว่านั่นคือสิ่งที่คนถามคำถามอยากรู้ เอกสารนั้นอธิบายถึงรูปแบบไฟล์คลาส (โค้ดไบต์ที่คอมไพล์) ไม่ใช่การแสดงตัวแปรบูลีนในหน่วยความจำเนื่องจากขึ้นอยู่กับการนำไปใช้งาน
William Brendel

2

ขนาดของบูลีนใน java ขึ้นอยู่กับเครื่องเสมือน แต่อ็อบเจ็กต์ Java ใด ๆ จะถูกจัดแนวให้มีความละเอียด 8 ไบต์ บูลีนมีส่วนหัว 8 ไบต์พร้อมด้วยเพย์โหลด 1 ไบต์สำหรับข้อมูลทั้งหมด 9 ไบต์ จากนั้น JVM จะปัดเศษขึ้นเป็นผลคูณถัดไปของ 8 ดังนั้นหนึ่งอินสแตนซ์ของ java.lang.Boolean จะใช้หน่วยความจำ 16 ไบต์


ฉันมักจะไม่เห็นด้วยใน HotSpot JVM 1.7.0_51 ส่วนหัวมี 12 ไบต์ + 1 สำหรับบูลีน + 3 สำหรับความละเอียด
ยูจีน

14
อย่าสับสนระหว่างบูลีนกับบูลีน
andresp

1
ไบต์หรือบิต? 16 ไบต์สำหรับBooleanwold นั้นเสียเปล่า ... นั่นคือขนาดlongที่สามารถรับข้อมูลได้มากกว่า aBoolean
Dici

0

มันไม่ได้กำหนด; การทำสิ่งต่างๆอย่างที่ Jon Skeet แนะนำจะทำให้คุณได้รับค่าประมาณบนแพลตฟอร์มที่กำหนด แต่วิธีที่จะทราบได้อย่างแม่นยำสำหรับแพลตฟอร์มเฉพาะคือการใช้ profiler

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.