Java เป็นภาษาคอมไพล์หรือแปลเป็นภาษาโปรแกรมหรือไม่


169

ในอดีตฉันใช้ภาษา C ++ เป็นภาษาโปรแกรม ฉันรู้ว่ารหัสที่เขียนใน C ++ ต้องผ่านกระบวนการรวบรวมจนกว่ามันจะกลายเป็นรหัสวัตถุ "รหัสเครื่อง"

ฉันอยากรู้ว่า Java ทำงานอย่างไรในแง่นั้น ผู้ใช้เขียนโค้ด Java เรียกใช้โดยคอมพิวเตอร์อย่างไร


14
สามารถแปล C ++ ได้ มีล่ามภาษาซีอยู่สองสามตัว
Tom Hawtin - tackline

คำตอบ:


220

Java implementations มักจะใช้กระบวนการรวบรวมสองขั้นตอน ซอร์สโค้ด Java ถูกคอมไพล์ลงไปเป็นbytecodeโดยคอมไพเลอร์ Java bytecode ดำเนินการโดย Java Virtual Machine (JVM) JVM สมัยใหม่ใช้เทคนิคที่เรียกว่าการรวบรวม Just-in-Time (JIT)เพื่อรวบรวม bytecode ไปยังคำสั่งพื้นฐานที่เข้าใจโดยซีพียูฮาร์ดแวร์ในทันทีที่รันไทม์

การใช้งานบางอย่างของ JVM อาจเลือกตีความรหัสไบต์แทนการรวบรวม JIT ให้เป็นรหัสเครื่องและเรียกใช้โดยตรง ในขณะนี้ยังถือว่าเป็น "ล่าม" มันค่อนข้างแตกต่างจากล่ามที่อ่านและรันซอร์สโค้ดระดับสูง (เช่นในกรณีนี้ซอร์สโค้ด Java ไม่ถูกตีความโดยตรง bytecode เอาต์พุตของคอมไพเลอร์ Java คือ)

มีความเป็นไปได้ทางเทคนิคในการรวบรวม Java ลงในรหัสเนทีฟล่วงหน้าและรันไบนารีผลลัพธ์ นอกจากนี้ยังเป็นไปได้ที่จะตีความรหัส Java โดยตรง

เพื่อสรุปโดยขึ้นอยู่กับสภาพแวดล้อมการดำเนินการ bytecode สามารถ:

  • เรียบเรียงล่วงหน้าและดำเนินการเป็นรหัสเนทีฟ (คล้ายกับคอมไพเลอร์ C ++ ส่วนใหญ่)
  • รวบรวมเพียงแค่ในเวลาและดำเนินการ
  • ตีความ
  • ดำเนินการโดยตรงโดยโปรเซสเซอร์ที่รองรับ (bytecode เป็นชุดคำสั่งพื้นฐานของ CPU บางตัว)

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

1
ดังนั้นคำว่า 'ฮอตสปอต' :) มันเป็นสิ่งที่ทำงานอยู่บ่อยครั้งเพื่อเพิ่มประสิทธิภาพ
ผ้าไหมเที่ยง

4
คุณสามารถปิดล่ามใน HotSpot ด้วย -Xcomp ควรลองใช้แอปพลิเคชันเพื่อดูว่าเป็นความคิดที่ไม่ดี
Tom Hawtin - tackline

1
มีคำแถลงว่า "เวอร์ชั่นปัจจุบันของ Sun HotSpot JVM ใช้เทคนิคที่เรียกว่าการรวบรวม Just-in-time (JIT) เพื่อคอมไพล์รหัสไบต์ให้กับคำสั่งดั้งเดิมที่เข้าใจโดยซีพียูในขณะใช้งาน" ฉันรู้สึกว่า JVM เป็นล่าม แต่มันแนะนำให้รวบรวมรหัสไบต์ ฉันสับสน. นอกจากนี้ยังมีการเขียนว่ามันทำทันทีที่รันไทม์ บางคนสามารถอธิบายเรื่องนี้ได้หรือไม่
อานันท์

เนื่องจาก java เป็นภาษาที่ตีความแล้วจะมีผลกับประสิทธิภาพการทำงานหรือการประมวลผลแอปพลิเคชันใด ๆ ของ Java อย่างไร
NAND

93

ป้อนคำอธิบายรูปภาพที่นี่

รหัสที่เขียนใน Java คือ:

  • คอมไพล์ครั้งแรกเป็น bytecode โดยโปรแกรมที่เรียกว่าjavacดังที่แสดงในส่วนด้านซ้ายของภาพด้านบน
  • จากนั้นดังที่แสดงในส่วนด้านขวาของอิมเมจด้านบนโปรแกรมอื่นที่เรียกว่าjavaเริ่มต้นสภาพแวดล้อมรันไทม์ของ Java และมันอาจรวบรวมและ / หรือตีความ bytecode โดยใช้ Java Interpreter / JIT Compiler

java ตีความตีความ bytecode เมื่อใดและจะรวบรวมเมื่อใด รหัสแอปพลิเคชันจะถูกตีความในขั้นต้น แต่ JVM จะตรวจสอบว่าลำดับของ bytecode ใดที่ถูกเรียกใช้งานบ่อยครั้งและแปลเป็นรหัสเครื่องสำหรับการดำเนินการโดยตรงบนฮาร์ดแวร์ สำหรับ bytecode ซึ่งดำเนินการเพียงไม่กี่ครั้งสิ่งนี้จะช่วยประหยัดเวลาในการรวบรวมและลดเวลาแฝงเริ่มต้น สำหรับ bytecode ที่ถูกเรียกใช้งานบ่อยครั้งการคอมไพล์ JIT ถูกใช้เพื่อรันด้วยความเร็วสูงหลังจากเฟสแรกของการตีความช้า นอกจากนี้เนื่องจากโปรแกรมใช้เวลาส่วนใหญ่ในการประมวลผลส่วนน้อยของรหัสเวลาในการรวบรวมที่ลดลงจึงมีความสำคัญ ในที่สุดในระหว่างการตีความรหัสเริ่มต้นสถิติการดำเนินการสามารถรวบรวมได้ก่อนการรวบรวมซึ่งช่วยในการเพิ่มประสิทธิภาพที่ดีขึ้น


มันเป็นเพราะ bytecode ที่แคชไว้ Java ใช้หน่วยความจำจำนวนมากหรือไม่
Pedro Gordo

3
@sedulam: 'หน่วยความจำมาก' เป็นคำสั่งที่คลุมเครือ การจัดการหน่วยความจำของ Java ค่อนข้างตรงไปตรงมา - สามชั่วอายุคนเป็นสิ่งที่ JVM ใช้สำหรับการสร้างและบำรุงรักษาวัตถุ คำตอบ SO อื่นนี้อาจเป็นประโยชน์สำหรับคุณ
displayName

ด้วยคำอธิบายข้างต้นตามหลักวิชาแล้วรหัสที่คอมไพล์ด้วยภาษา C ++ จะต้องเร็วกว่าโค้ดจาวาที่คล้ายกันอย่างมีเหตุผลเนื่องจากจะมีไฟล์. class บางส่วนที่ JIT ตัดสินใจที่จะไม่แปลงเป็นรหัสเครื่อง กล่าวอีกนัยหนึ่ง java ไม่สามารถจับความเร็วในการประมวลผลโลหะเปลือยเปล่าที่ C ++ แสดงให้เห็นได้ สมมติฐานนี้ถูกต้องหรือไม่?
DevdattaK

@DevdattaK: ฉันไม่รู้ C ++ มากนัก แต่ฉันเดาว่าสำหรับโปรแกรมขนาดเล็กและพิเศษ Java อาจให้ผลลัพธ์เร็วขึ้นเพราะจะไม่เสียเวลาในการรวบรวมส่วนของรหัสที่ไม่มีความเร็วมากนัก
displayName

1
@DevdattaK สมมติฐานของคุณจะถูกกล่าวถึงในหน้าวิกินี้en.m.wikipedia.org/wiki/Java_performance?wprov=sfla1 ในระยะสั้นก็ไม่เป็นความจริงเสมอ
Sundar Rajan

57

คำว่า "ตีความภาษา" หรือ "ภาษารวบรวม" ไม่สมเหตุสมผลเพราะภาษาการเขียนโปรแกรมใด ๆ ที่สามารถตีความและ / หรือรวบรวม

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

วันนี้การรวบรวมแบบทันเวลาบางส่วนใช้สำหรับหลายภาษาซึ่งครั้งหนึ่งเคยถูกพิจารณาว่า "ตีความ" เช่น JavaScript


5
นอกจากนี้เครื่องมือประมวลผล V8 JavaScript ของ Google ไม่เพียง แต่ทำการรวบรวมเพียงบางส่วนเท่านั้น มันมักจะคอมไพล์กับรหัสเนทีฟในความเป็นจริง V8 ไม่ได้มีล่าม มันมีเพียงคอมไพเลอร์ (คล้ายกับ Maxine แต่ต่างจาก Maxine V8 มีคอมไพเลอร์เพียงตัวเดียว) ตัวอย่างทั้งสามเหล่านี้ (GCJ, Maxine และ V8) พิสูจน์จุดของคุณได้ดียิ่งขึ้น: ไม่มีสิ่งใดในภาษาที่ตีความหรือภาษาที่รวบรวม ภาษาไม่ได้แปลหรือเรียบเรียง ภาษาก็คือ (จริง ๆ แล้วเป็นคำพูดของ Shriram Krishnamurthi)
Jörg W Mittag

3
ทำไมคุณถึงพูดถึงจาวาสคริปต์ในคำถามจาวา?
Koray Tugay

1
@KorayTugay เป็นเพียงตัวอย่าง ฉันไม่ต้องการบอกเป็นนัยว่า Java และ Javascript มีอะไรที่เหมือนกันนอกเหนือจากตัวอักษรสี่ตัวแรกของชื่อ
starblue

อย่างน้อยจะมีความแตกต่างในภาษาที่แปลและเรียบเรียงไม่ได้หมายความว่าไบนารีภาษาที่คอมไพล์ไม่สามารถเปลี่ยนการไหลของการดำเนินการได้ตลอดเวลาในขณะที่ภาษาที่ตีความจะเชื่อฟังงานบางอย่างของฟังก์ชั่นปัจจุบันหรือไม่? ไลบรารี่ใน C เป็นตัวเลือกในขณะที่ในภาษาอื่นคุณไม่สามารถมีอาเรย์ออบเจ็กต์ได้หากไม่มีส่วนขยายไบนารี C ที่สามารถอัปเดตหรือเป็นรหัสที่แตกต่างอย่างสิ้นเชิงในแพลตฟอร์มอื่น ภาษาสคริปต์จะสามารถทำงานได้ทั้งสองในขณะที่ภาษาที่รวบรวมจะต้องมีไบนารีที่แตกต่างกันเพื่อให้ทำงานได้
Eaton Emmerich

53

Java ถูกคอมไพล์ไปยัง bytecode ซึ่งจะไปสู่ ​​Java VM ซึ่งแปลความหมายนั้น


33
... แต่ไม่แม่นยำอย่างแน่นอน
สตีเฟ่นซี

2
JVM อาจเลือกที่จะไม่ "ตีความ" bytecode มันสามารถรวบรวม JIT และดำเนินการโดยตรง
Mehrdad Afshari

1
JIT ไม่ได้ดำเนินการทางเทคนิคโดยตรง มันแค่จำได้ว่ามันถูกประหารชีวิตอย่างไร
cletus

Mehrdad: ตกลงผมไม่ได้อธิบายการดำเนินงานอาจ JIT นี่เป็นผมคิดว่าขึ้นอยู่กับ JVM นั้นและผมได้รับการรักษาคำตอบง่ายๆของฉันอยู่แล้ว :)
เที่ยงไหม

7
cletus: หลังจาก JIT มันจะถูกดำเนินการโดยตรง JIT กำลังอ่านส่วนหนึ่งของไบต์ (เช่นวิธีการที่สมบูรณ์ ) และรวบรวมลงไปในรหัสเครื่องและกระโดดไปที่มัน
Mehrdad Afshari

12

Java เป็นภาษาการเขียนโปรแกรมที่คอมไพล์ แต่แทนที่จะคอมไพล์ตรงไปยังโค้ดเครื่องที่เรียกทำงานได้มันจะคอมไพล์เป็นรูปแบบไบนารีกลางที่เรียกว่ารหัสไบต์ JVM จากนั้นโค้ดไบต์จะถูกคอมไพล์และ / หรือตีความเพื่อรันโปรแกรม


11

ชนิดของทั้งสอง เริ่มแรกรวบรวม Java (บางคนชอบที่จะพูดว่า "แปล") เพื่อ bytecode ซึ่งจากนั้นรวบรวมหรือตีความขึ้นอยู่กับอารมณ์ของ JIT


32
นั่นเป็นชิ้นขั้นสูงของซอฟแวร์ที่จะมีอารมณ์ที่พัฒนาแล้ว :)
Thorarin

5
JIT นั้นเป็นซอฟต์แวร์ที่มีความซับซ้อนมากซึ่งสามารถทำการปรับให้เหมาะสมตามข้อมูลรันไทม์ (เช่น profiler) ซึ่งคอมไพเลอร์ล่วงหน้าไม่สามารถทำได้ (เพราะไม่มีข้อมูลเกี่ยวกับพฤติกรรมรันไทม์ของ โปรแกรมล่วงหน้า) แต่มันอาจจะไม่ได้จริงๆมีอารมณ์ ... :-)
Jesper

5

Java ทำการรวบรวมและตีความ

ใน Java โปรแกรมไม่ได้เรียบเรียงไฟล์ปฏิบัติการ ; พวกเขาจะรวบรวมเป็น bytecode (ตามที่กล่าวไว้ก่อนหน้า) ซึ่ง JVM (Java Virtual Machine) จากนั้นตีความ / รันที่รันไทม์ ซอร์สโค้ด Java ถูกคอมไพล์เป็น bytecode เมื่อเราใช้คอมไพเลอร์ javac bytecode ได้รับการบันทึกไว้ในดิสก์ด้วยนามสกุลไฟล์. class.class

เมื่อโปรแกรมจะถูกเรียกใช้bytecode จะถูกแปลง bytecode อาจถูกแปลงโดยใช้คอมไพเลอร์ just-in-time (JIT) ผลลัพธ์คือรหัสเครื่องซึ่งถูกป้อนเข้าสู่หน่วยความจำและดำเนินการ

Javacเป็นJava Compilerซึ่งรวบรวมโค้ด Java ลงใน Bytecode JVM เป็น Java Virtual Machine ที่รัน / ตีความ / แปล Bytecode เป็น Native Machine Code ใน Java แม้ว่ามันจะถือเป็นภาษาตีความมันอาจใช้การรวบรวม JIT (Just-in-Time) เมื่อ bytecode อยู่ใน JVM คอมไพเลอร์ JIT อ่าน bytecode ในหลายส่วน (หรือเต็มไม่ค่อย) และรวบรวมไว้ในโค้ดของเครื่องจักรแบบไดนามิกเพื่อให้โปรแกรมสามารถทำงานได้เร็วขึ้นจากนั้นแคชและนำมาใช้ใหม่ในภายหลังโดยไม่จำเป็นต้องทำการคอมไพล์ใหม่ ดังนั้นการคอมไพล์ JIT จะรวมความเร็วของโค้ดที่คอมไพล์ด้วยความยืดหยุ่นในการตีความ

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

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

ในการใช้ภาษาโปรแกรมที่ทันสมัยเช่นใน Java มันเป็นที่นิยมมากขึ้นสำหรับแพลตฟอร์มเพื่อให้ทั้งสองตัวเลือก


ควรเป็น "ไบต์อาจแปลง" มากกว่า " ถูกแปลง" Java specs กำหนด bytecode ไม่ว่า bytecode จะถูกเรียกใช้ (a) โดยตรงในฮาร์ดแวร์ (b) ผ่านล่าม, (c) รวบรวมไว้ล่วงหน้าหรือ (d) คอมไพล์บางส่วนที่ on-the-fly ที่รันไทม์จะถูกทิ้งไว้เป็นรายละเอียดการนำไปปฏิบัติ โปรดทราบว่าตัวเลือกทั้งสี่นั้นได้ถูกใช้งานโดยการใช้งานจาวาจริง ๆ
Basil Bourque

ขอบคุณที่ชี้นำสิ่งนี้ ดังนั้นจะเกิดอะไรขึ้นหากรหัสไบต์ไม่ได้ถูกแปลงเป็นรหัสเครื่อง? ฉันสามารถนึกถึงสถานการณ์ที่ bytecode เป็นชุดคำสั่งพื้นฐานสำหรับโปรเซสเซอร์บางตัวและจากนั้นไม่จำเป็นต้องมีการแปลง หรือฉันกำลังคิดถึงบางสิ่งอยู่
เฉพาะ

คลิกลิงก์ที่ฉันให้ไว้กับเทคโนโลยีJazelle DBX (Direct Bytecode eXecution)ซึ่งเซตย่อยของ JVM bytecode เป็นคำสั่งของเครื่องเนทีฟของ CPU (kinda-sorta) หากปราศจากสิ่งนั้นคุณจะได้รับรหัสเครื่องที่สร้างจาก bytecode (a) จากล่าม (ทันที) (b) จากผู้รวบรวมก่อนเวลาหรือ (c) on-the-fly พร้อมกับผู้เรียบเรียงแบบทันเวลา ( ตีความในตอนแรกและบางครั้งก็รวบรวมและแคชในระหว่างการดำเนินการ)
Basil Bourque

-2

Java เป็นภาษาที่คอมไพล์ด้วยการกำหนดเป้าหมายเป็นแพลตฟอร์มที่เรียกว่าJava Virtual Machineซึ่งเป็นแบบสแต็กและมีการใช้งานที่รวดเร็วมากในหลาย ๆ แพลตฟอร์ม


1
"คอมไพล์ไบต์" หมายความว่าอะไร?
Jesper

2
@Jesper: "Byte-compiled" มักจะหมายถึง "compiled to bytecode" "Bytecode" เป็นคำทั่วไปที่ครอบคลุมการเรียงลำดับใด ๆ ของรหัสกลางที่ไม่ใช่ข้อความ (โดยทั่วไปไม่สามารถใช้กับเครื่อง)
Greg Hewgill

-3

ใบเสนอราคาจาก: https://blogs.oracle.com/ask-arun/entry/run_your_java_applications_faster

ผู้พัฒนาแอพพลิเคชั่นสามารถพัฒนารหัสแอพพลิเคชั่นบนระบบปฏิบัติการที่หลากหลายที่มีอยู่ในตลาดปัจจุบัน ภาษา Java นั้นไม่เชื่อเรื่องพระเจ้าในระยะนี้กับระบบปฏิบัติการ ซอร์สโค้ดที่ยอดเยี่ยมที่เขียนโดยนักพัฒนา Java Application ตอนนี้ได้รับการคอมไพล์ไปยังโค้ด Java Byte ซึ่งในศัพท์ภาษาจาวาเรียกว่าการคอมไพล์ฝั่งไคลเอ็นต์ การรวบรวมโค้ด Java Byte นี้เป็นสิ่งที่ช่วยให้นักพัฒนา Java สามารถ 'เขียนครั้งเดียว' รหัส Java Byte สามารถเรียกใช้บนระบบปฏิบัติการและเซิร์ฟเวอร์ที่รองรับใด ๆ จึงทำให้ซอร์สโค้ดไม่เชื่อเรื่อง OS / Server โพสต์การสร้างโค้ด Java Byte การโต้ตอบระหว่างแอ็พพลิเคชัน Java และ OS / Server พื้นฐานนั้นใกล้ชิดยิ่งขึ้น การเดินทางยังดำเนินต่อไป - เฟรมเวิร์กแอปพลิเคชันระดับองค์กรดำเนินการโค้ด Java Byte เหล่านี้ในสภาพแวดล้อมรันไทม์ซึ่งรู้จักกันในนาม Java Virtual Machine (JVM) หรือ Java Runtime Environment (JRE) JVM มีความสัมพันธ์ใกล้ชิดกับระบบปฏิบัติการและฮาร์ดแวร์พื้นฐานเพราะใช้ประโยชน์จากทรัพยากรที่มีให้โดยระบบปฏิบัติการและเซิร์ฟเวอร์ โค้ด Java Byte ได้รับการคอมไพล์ในขณะที่รหัสภาษาที่ใช้งานได้ของเครื่องซึ่งเป็นแพลตฟอร์มเฉพาะ สิ่งนี้เรียกว่าการรวบรวมฝั่งเซิร์ฟเวอร์

ดังนั้นฉันจะบอกว่า Java เป็นภาษาที่รวบรวมแน่นอน

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