กำลังวิเคราะห์การใช้หน่วยความจำ: Java vs C ++ เล็กน้อย


9

การใช้หน่วยความจำของวัตถุจำนวนเต็มที่เขียนใน Java เปรียบเทียบ \ contrast กับการใช้หน่วยความจำของวัตถุจำนวนเต็มที่เขียนใน C ++ อย่างไร ความแตกต่างเล็กน้อยหรือไม่ ไม่แตกต่าง? ความแตกต่างใหญ่? ฉันคาดเดาว่ามันเหมือนกันเพราะ int เป็น int โดยไม่คำนึงถึงภาษา (?)

เหตุผลที่ฉันถามสิ่งนี้เพราะฉันกำลังอ่านเกี่ยวกับความสำคัญของการรู้ว่าข้อกำหนดหน่วยความจำของโปรแกรมเมื่อใดจะทำให้โปรแกรมเมอร์ไม่สามารถแก้ไขปัญหาที่กำหนดได้

สิ่งที่ทำให้ฉันหลงใหลคือจำนวนหน่วยความจำที่จำเป็นสำหรับการสร้างวัตถุ Java ชิ้นเดียว ยกตัวอย่างเช่นวัตถุจำนวนเต็ม แก้ไขให้ฉันถ้าฉันผิด แต่วัตถุจำนวนเต็ม Java ต้องการหน่วยความจำ 24 ไบต์:

  • 4 ไบต์สำหรับตัวแปรอินสแตนซ์ของมัน
  • 16 ไบต์ของค่าใช้จ่าย (อ้างอิงถึงคลาสของวัตถุข้อมูลการรวบรวมขยะ & ข้อมูลการซิงโครไนซ์)
  • การซ้อน 4 ไบต์

เป็นอีกตัวอย่างหนึ่งอาร์เรย์ Java (ซึ่งถูกนำมาใช้เป็นวัตถุ) ต้องการ 48 + ไบต์:

  • ข้อมูลส่วนหัว 24 ไบต์
  • ค่าใช้จ่ายของวัตถุ 16 ไบต์
  • ความยาว 4 ไบต์
  • 4 ไบต์สำหรับการขยาย
  • รวมทั้งหน่วยความจำที่จำเป็นในการจัดเก็บค่า

หน่วยความจำเหล่านี้ใช้อย่างไรเปรียบเทียบกับรหัสเดียวกันที่เขียนใน C ++

ฉันเคยหลงลืมเกี่ยวกับการใช้หน่วยความจำของโปรแกรม C ++ และ Java ที่ฉันเขียน แต่ตอนนี้ฉันเริ่มเรียนรู้เกี่ยวกับอัลกอริทึมแล้วฉันรู้สึกซาบซึ้งยิ่งขึ้นกับทรัพยากรของคอมพิวเตอร์


6
"วัตถุจำนวนเต็ม" ใน C ++ คืออะไร int? ถ้าเป็นเช่นนั้นคุณควรเปรียบเทียบกับintใน Java ไม่ใช่Integer- ตราบใดที่ C ++ ints ของคุณคือ 32 บิต
Mat

+1 ถ้าฉันสร้างคลาส c ++ ที่มีตัวแปร int เพียงตัวเดียวดังนั้นอินสแตนซ์มัน
Anthony

3
int ไม่ได้เป็น int - มันขึ้นอยู่กับแพลตฟอร์ม

1
C ++ ที่มีสมาชิก int เพียงคนเดียวโดยทั่วไปจะไม่มีค่าใช้จ่ายใด ๆ มันจะใช้พื้นที่มากพอ ๆ กับที่แพลตฟอร์มใช้เพื่อเก็บ int (โดยทั่วไปคือ 4 ไบต์บนแพลตฟอร์มพีซีปัจจุบัน)
Dirk Holsopple

+1 สำหรับโปรแกรมเมอร์ Java ที่สงสัยเกี่ยวกับหน่วยความจำ ยิ่งกว่าสิ่งอื่นใดการตระหนักถึงความจำเป็นปัจจัยที่สำคัญที่สุดที่กำหนดประสิทธิภาพของสถาปัตยกรรมสมัยใหม่
imallett

คำตอบ:


15

มันขึ้นอยู่กับแพลตฟอร์มและการใช้งาน

C ++ รับประกันได้ว่าขนาดของcharนั้นเท่ากับหนึ่งไบต์และกว้างอย่างน้อย 8 บิต แล้วขนาดของshort intเป็นอย่างน้อย 16 charบิตและไม่ได้มีขนาดเล็กกว่า ขนาดของอย่างน้อยเป็นใหญ่เป็นขนาดของint short intขนาดlong intอย่างน้อย 32 บิตและไม่เล็กกว่า int

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

โมเดลหน่วยความจำจริงของ C ++ นั้นกะทัดรัดและคาดเดาได้มาก ตัวอย่างเช่นไม่มีข้อมูลเมตาในวัตถุอาร์เรย์หรือพอยน์เตอร์ โครงสร้างและชั้นเรียนมีความต่อเนื่องเหมือนกันกับอาร์เรย์ แต่อาจมีการขยายเพิ่มเติมหากจำเป็นและจำเป็น

แม้ว่าการเปรียบเทียบดังกล่าวจะโง่ที่สุดเมื่อการใช้หน่วยความจำ Java ขึ้นอยู่กับการนำ Java ไปใช้มากกว่าโค้ดที่รัน


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

หมายเหตุ OP: คุณอาจจะดีกว่าการเลือกตัวเองขนาดของจำนวนเต็ม - ถ้าคุณต้องการ int 32 บิตใน C ++ int32_tคุณสามารถใช้
K.Steff

9

คำตอบส่วนใหญ่ดูเหมือนจะไม่สนใจประเด็นสำคัญสองสามข้อ

อันดับแรกใน Java ที่แย่มากคุณแทบไม่เคยเห็นข้อมูลดิบint- เกือบทั้งหมดใช้เป็นของIntegerดังนั้นความจริงที่ว่าขนาดintอาจเท่ากับ (ประมาณ) เท่ากับintC หรือ C ++ เกือบจะไม่เกี่ยวข้องยกเว้นว่า ( จากประสบการณ์ของฉันเปอร์เซ็นต์ของโค้ดขนาดเล็กที่ใช้intแทนIntegerเท่านั้น

ประการที่สองขนาดของวัตถุแต่ละรายการแทบไม่เกี่ยวกับรอยความทรงจำของโปรแกรมโดยรวม ใน Java footprint หน่วยความจำของโปรแกรมเกี่ยวข้องเป็นหลักกับวิธีที่ตัวรวบรวมขยะได้รับการปรับแต่ง ในกรณีส่วนใหญ่ GC ได้รับการปรับเพื่อเพิ่มความเร็วสูงสุดซึ่งส่วนใหญ่หมายถึงการรัน GC ไม่บ่อยเท่าที่จะเป็นไปได้

ฉันยังไม่มีลิงค์ในขณะนี้ แต่มีการทดสอบบางอย่างที่แสดงว่า Java สามารถวิ่งด้วยความเร็วเดียวกับ C แต่ต้องทำเช่นนั้นคุณต้องรัน GC ไม่ค่อยเพียงพอที่จะใช้ประมาณ 7 ครั้ง หน่วยความจำ นั่นไม่ใช่เพราะวัตถุแต่ละชิ้นมีขนาดใหญ่กว่า 7 เท่า แต่เนื่องจาก GC อาจมีราคาแพงหากคุณทำบ่อยเกินไป ยิ่งไปกว่านั้น GC สามารถปล่อยหน่วยความจำได้ก็ต่อเมื่อสามารถ "พิสูจน์" ว่าไม่มีทางเข้าถึงวัตถุได้อีกต่อไปแทนที่จะเป็นเพียงเมื่อคุณรู้ว่าคุณใช้งานเสร็จแล้ว ซึ่งหมายความว่าแม้ว่าคุณจะเรียกใช้ GC บ่อยขึ้นเพื่อลดการใช้หน่วยความจำให้น้อยที่สุดคุณก็ยังสามารถวางแผนในโปรแกรมทั่วไปที่มีหน่วยความจำขนาดใหญ่กว่า ในกรณีเช่นนี้คุณอาจลดตัวประกอบเป็น 2 หรือ 3 แทนที่จะเป็น 7 แม้ว่าคุณจะลงน้ำอย่างมากอย่างไรก็ตาม1 .

ขึ้นอยู่กับสถานการณ์มีปัจจัยอื่นที่อาจหรือไม่สำคัญ: หน่วยความจำครอบครองโดย JVM เอง นี่คือการแก้ไขมากหรือน้อยดังนั้นร้อยละอาจมีขนาดใหญ่ถ้าแอปไม่ต้องการที่เก็บข้อมูลของตัวเองมากหรืออาจจะจิ๋วถ้าแอพจำเป็นต้องเก็บจำนวนมาก อย่างน้อยในเครื่องของฉันแม้แต่แอพ Java ที่น่าสนใจที่สุดก็ดูเหมือนจะครอบครองบางสิ่งบางอย่างเช่น 20-25 เมกะไบต์ (อาจมากกว่า 1,000 เท่าสำหรับโปรแกรม trivlal หรือเกือบจะเล็กมากสำหรับโปรแกรมขนาดใหญ่)


1ไม่ได้หมายความว่าไม่มีใครสามารถจัดการเขียน Java ด้วย footprint ที่ใกล้เคียงกับสิ่งที่คุณจะได้รับด้วย C ++ มันเป็นเพียงที่จะบอกว่าเพียงแค่มีเดียวกันจำนวน / ขนาดของวัตถุและทำงาน GC บ่อยจริงๆจะไม่ได้รับคุณมีเป็นกฎ


7
เกี่ยวกับจุดแรกของคุณ: ฉันไม่มีผู้ชาย Java แต่ Java API ที่ผมเคยเห็นไม่เคยใช้Integer(ทำไมพวกเขาจะ?) intแทน เฉพาะคอลเลกชันทั่วไปเท่านั้นที่ไม่มีทางเลือกนอกจากต้องใช้Integerเนื่องจากการลบประเภท แต่ถ้าคุณสนใจคุณสามารถแทนที่คอลเลกชันเหล่านั้นด้วยการติดตั้งแบบพิเศษintหรือประเภทดั้งเดิมที่คุณต้องการ แล้วมีการชกมวยชั่วคราวสำหรับการส่งรหัสการห่อทั่วไป (เช่นทุกอย่างที่ต้องมีObject[]) นอกจากนั้นคุณมีแหล่งที่มาสำหรับค่าใช้จ่ายในพื้นที่ GC หรือไม่ ฉันไม่สงสัยเลยจริงๆฉันแค่อยากรู้


9

ฉันหวังว่าคุณจะเข้าใจว่าสิ่งเหล่านี้เป็นสิ่งที่กำหนดไว้อย่างลึกล้ำทั้งสำหรับ Java และ C ++ ดังที่ได้กล่าวไปแล้วโมเดลวัตถุของ Java ต้องการพื้นที่ค่อนข้างน้อย

วัตถุ C ++ ไม่ได้ (โดยทั่วไป) ต้องการหน่วยเก็บข้อมูลใด ๆยกเว้นสิ่งที่สมาชิกต้องการ โปรดทราบว่า (ซึ่งแตกต่างจาก Java ที่ทุกอย่างที่ผู้ใช้กำหนดเป็นประเภทการอ้างอิง) รหัสลูกค้าสามารถใช้วัตถุทั้งเป็นประเภทค่าหรือเป็นประเภทการอ้างอิงเช่นวัตถุสามารถเก็บตัวชี้ / การอ้างอิงไปยังวัตถุอื่นหรือเก็บวัตถุโดยตรง ไม่มีทางอ้อม จำเป็นต้องใช้ตัวชี้เพิ่มเติมต่อวัตถุหากมีvirtualวิธีการใด ๆแต่มีเพียงไม่กี่คลาสที่มีประโยชน์ถูกออกแบบมาให้เข้ากันได้โดยไม่ต้องมีความหลากหลายและไม่ต้องการสิ่งนี้ ไม่มีเมตาดาต้า GC และไม่มีการล็อคสำหรับแต่ละวัตถุ ดังนั้นclass IntWrapper { int x; public: IntWrapper(int); ... };วัตถุไม่จำเป็นต้องมีพื้นที่ว่างมากกว่าints ธรรมดาและสามารถวางโดยตรง (เช่นไม่มีทิศทาง) ในคอลเลกชันและวัตถุอื่น ๆ

อาเรย์เป็นเรื่องยากเพราะไม่มีการสร้างล่วงหน้าเทียบเท่ากับ Java Array ใน C ++ คุณสามารถจัดสรรวัตถุจำนวนมากด้วยnew[](โดยไม่มีค่าใช้จ่าย / ข้อมูลเมตา) แต่ไม่มีเขตข้อมูลความยาวการใช้งานอาจเก็บไว้ แต่คุณไม่สามารถเข้าถึงได้ std::vectorเป็นอาร์เรย์แบบไดนามิกจึงมีค่าใช้จ่ายเพิ่มเติมและอินเทอร์เฟซที่ใหญ่กว่า std::arrayและอาร์เรย์สไตล์ C (int arr[N];) ต้องมีการรวบรวมเวลาคงที่ ในทางทฤษฎีแล้วมันควรจะเป็นเพียงแค่ที่เก็บข้อมูลของวัตถุบวกกับจำนวนเต็มเดียวสำหรับความยาว - แต่เนื่องจากคุณสามารถปรับขนาดแบบไดนามิกและอินเทอร์เฟซที่มีคุณสมบัติครบถ้วนพร้อมพื้นที่พิเศษเล็ก ๆ น้อย ๆ โปรดทราบว่าสิ่งเหล่านี้รวมถึงคอลเลกชันอื่น ๆ ทั้งหมดเป็นค่าเริ่มต้นในการจัดเก็บวัตถุตามค่าซึ่งช่วยให้คุณประหยัดโดยอ้อมและพื้นที่สำหรับการอ้างอิงและปรับปรุงพฤติกรรมแคช คุณต้องจัดเก็บพอยน์เตอร์ (สมาร์ทตัวโปรดโปรด) เพื่อรับทิศทาง

การเปรียบเทียบด้านบนนี้ไม่ยุติธรรมเลยเพราะการประหยัดบางอย่างนั้นไม่ได้รวมคุณสมบัติของ Java ไว้ด้วยและการเทียบเคียง C ++ มักจะได้รับการปรับให้เหมาะสมน้อยกว่า Java เทียบเท่า (*) วิธีทั่วไปในการนำไปใช้virtualใน C ++ จะกำหนดค่าใช้จ่ายเท่า ๆ กับวิธีทั่วไปในการนำไปใช้virtualใน Java ในการรับล็อคคุณต้องมีวัตถุ mutex ที่มีคุณสมบัติครบถ้วนซึ่งมีขนาดใหญ่กว่าสองสามบิต เพื่อรับการอ้างอิงนับ ( ไม่เทียบเท่า GC และไม่ควรใช้เช่นนี้ แต่บางครั้งก็มีประโยชน์) คุณต้องมีตัวชี้สมาร์ทซึ่งจะเพิ่มฟิลด์จำนวนการอ้างอิง เว้นแต่ว่าวัตถุจะถูกสร้างอย่างระมัดระวังจำนวนการอ้างอิงวัตถุตัวชี้สมาร์ทและวัตถุที่อ้างอิงอยู่ในสถานที่ที่แยกจากกันอย่างสมบูรณ์และแม้ว่าคุณจะสร้างมันถูกต้องตัวชี้ที่ใช้ร่วมกันอาจ (ต้อง?) ยังคงเป็นสองตัวชี้แทนหนึ่ง จากนั้นอีกครั้งสไตล์ C ++ ที่ดีไม่ได้ใช้คุณสมบัติเหล่านี้เพียงพอสำหรับการใช้งาน - ในทางปฏิบัติวัตถุของไลบรารี C ++ ที่เขียนได้ดีนั้นใช้น้อยกว่า ที่ไม่จำเป็นต้องใช้หน่วยความจำน้อยกว่าค่าเฉลี่ยโดยรวม แต่ไม่ได้หมายความ c ++ มีการเริ่มต้นที่ดีในเรื่องนี้

(*) ตัวอย่างเช่นคุณสามารถรับสายเสมือนรหัสแฮชเอกลักษณ์และการล็อคด้วยคำเดียวสำหรับวัตถุบางอย่าง (และสองคำสำหรับวัตถุอื่น ๆ อีกมากมาย) โดยการรวมข้อมูลประเภทกับค่าสถานะต่าง ๆ และเอาบิตล็อคสำหรับวัตถุที่ ไม่น่าจะต้องการล็อค ดูการใช้งาน Java Object Model (PDF) อย่างมีประสิทธิภาพและประหยัดเวลาโดย David F. Bacon, Stephen J. Fink และ David Grove สำหรับคำอธิบายโดยละเอียดเกี่ยวกับสิ่งนี้และการปรับให้เหมาะสมอื่น ๆ


3

ล้วนintในจาวาใช้พื้นที่เท่ากับintใน C ++ โดยที่การใช้งานทั้งสองใช้ขนาดจำนวนเต็มเดียวกันและการจัดตำแหน่งหน่วยความจำ

int 'object' ( จำนวนเต็มชนิดบรรจุกล่องนั่นคืออินสแตนซ์ของคลาสInteger) มีค่าใช้จ่ายทั้งหมดของคลาสอินสแตนซ์ใน Java จึงมีขนาดใหญ่กว่าintใน C ++ อย่างมีนัยสำคัญ อย่างไรก็ตามหากคุณต้องจัดเตรียมวัตถุใน C ++ ด้วยคุณสมบัติเดียวกับที่วัตถุ Java มาพร้อมกับกล่อง (polymorphism, box, box, garbage collection, RTTI) คุณอาจต้องจบด้วยวัตถุที่มีค่าเท่ากัน ขนาด.

แล้วมีข้อควรพิจารณาในการปรับให้เหมาะสม เนื่องจากรูปแบบการดำเนินการและกระบวนทัศน์การเขียนโปรแกรมแตกต่างกันจึงไม่น่าเป็นไปได้ที่ปัญหาที่ไม่สำคัญจะแก้ไขได้เหมือนกันทั้งสองภาษาดังนั้นการเปรียบเทียบขนาดพื้นที่เก็บข้อมูลในระดับนี้จึงไม่สมเหตุสมผลนัก

ใช่วัตถุ Java มีค่าใช้จ่ายมากกว่าค่าเริ่มต้นมากกว่าคลาส C ++ แต่มาพร้อมกับคุณสมบัติเพิ่มเติมและสิ่งนี้นำไปสู่รูปแบบการเขียนโปรแกรมที่แตกต่างกัน - โปรแกรมเมอร์ที่ดีสามารถใช้ประโยชน์จากภาษาทั้งสองขึ้นและลง


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