การใช้การแปลงซอร์สโค้ดเป็น Java bytecode คืออะไร


37

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


1
ซ้ำซ้อนที่เป็นไปได้ของการคอมไพล์ไปยัง bytecode vs รหัสเครื่อง
gnat

12
@gnat: จริง ๆ แล้วมันไม่ได้ซ้ำกัน นี่คือ "source vs byte code" คือการแปลงแรก ในแง่ภาษานี่คือ Javascript กับ Java; ลิงก์ของคุณจะเป็น C ++ กับ Java
MSalters

2
คุณต้องการที่จะเขียนล่าม bytecode อย่างง่าย ๆ สำหรับเครื่องใช้ไฟฟ้า 50 รุ่นที่คุณกำลังเพิ่มการเข้ารหัสดิจิทัลสำหรับการอัพเกรดหรือ 50 คอมไพเลอร์สำหรับฮาร์ดแวร์ 50 ตัว Java ถูกพัฒนาขึ้นครั้งแรกสำหรับเครื่องใช้และเครื่องจักร นั่นคือชุดสูทที่แข็งแกร่ง โปรดระลึกไว้เสมอว่าเมื่ออ่านคำตอบเหล่านี้เนื่องจาก Java ไม่มีข้อได้เปรียบที่แท้จริงในปัจจุบัน (เนื่องจากกระบวนการตีความไม่มีประสิทธิภาพ) เป็นเพียงรุ่นที่เราใช้ต่อไป
The Great Duck

1
คุณดูเหมือนจะไม่เข้าใจว่าเครื่องเสมือนคืออะไร มันเป็นเครื่อง มันสามารถนำมาใช้ในฮาร์ดแวร์ที่มีคอมไพเลอร์รหัสพื้นเมือง (และในกรณีของ JVM มันได้รับ) ส่วน 'เสมือนจริง' เป็นสิ่งสำคัญที่นี่: คุณกำลังจำลองสถาปัตยกรรมนั้นอยู่ด้านบนของอีกส่วนหนึ่ง สมมติว่าฉันเขียนโปรแกรมจำลอง 8088 เพื่อทำงานบน x86 คุณจะไม่ย้ายพอร์ตรหัส 8088 เก่าไปที่ x86 คุณเพียงแค่เรียกใช้บนแพลตฟอร์มจำลอง JVM เป็นเครื่องจักรที่คุณกำหนดเป้าหมายเหมือนกันความแตกต่างจะอยู่บนแพลตฟอร์มอื่น ๆ
Jared Smith

7
@TheGreatDuck กระบวนการตีความหรือไม่ JVM ส่วนใหญ่ทุกวันนี้ทำการคอมไพล์แบบทันเวลากับรหัสเครื่อง ไม่ต้องพูดถึงว่า "การตีความ" เป็นคำที่ค่อนข้างกว้างในทุกวันนี้ ซีพียูเองก็แค่ "ตีความ" รหัส x86 ไปเป็นไมโครโค้ดภายในของตัวเองและมันก็ถูกใช้เพื่อปรับปรุงประสิทธิภาพ Intel CPU รุ่นล่าสุดนั้นเหมาะอย่างยิ่งสำหรับล่ามโดยทั่วไปเช่นกัน (ถึงแม้ว่าคุณจะพบเกณฑ์มาตรฐานเพื่อพิสูจน์สิ่งที่คุณต้องการพิสูจน์)
Luaan

คำตอบ:


79

ตรรกะคือ JVM bytecode นั้นง่ายกว่าซอร์สโค้ด Java มาก

คอมไพเลอร์สามารถคิดได้ในระดับนามธรรมอย่างมีสามส่วนพื้นฐาน: แยกวิเคราะห์วิเคราะห์ความหมายและการสร้างรหัส

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

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

สิ่งนี้ทำให้ภารกิจที่ JIT ต้องดำเนินการง่ายกว่ามากและเร็วกว่ามากในการดำเนินการในขณะที่ยังคงรักษาข้อมูลเมตาระดับสูงและข้อมูลเชิงความหมายซึ่งทำให้สามารถเขียนโค้ดข้ามแพลตฟอร์มในทางทฤษฎีได้


7
ความพยายามในช่วงต้นอื่น ๆ ของการแจกจ่ายแอปเพล็ตเช่น SafeTCL จริง ๆ แล้วแจกจ่ายซอร์สโค้ด การใช้ bytecode อย่างง่ายและเจาะจงของจาวาทำให้การตรวจสอบโปรแกรมนั้นง่ายขึ้นและนั่นก็เป็นปัญหาที่ยากที่จะแก้ไข Bytecodes เช่น p-code นั้นเป็นที่รู้จักกันดีว่าเป็นส่วนหนึ่งของการแก้ปัญหาการพกพา (และ ANDF อาจอยู่ในการพัฒนาในเวลานั้น)
Toby Speight

9
แม่นยำ. เวลาเริ่มต้นของ Java เป็นปัญหาเล็กน้อยเนื่องจากขั้นตอน bytecode -> รหัสเครื่อง เรียกใช้ javac ในโปรเจ็กต์ (ไม่สำคัญ) ของคุณจากนั้นลองจินตนาการว่าทำโค้ด Java -> ทั้งเครื่องในทุกการเริ่มต้น
Paul Draper

24
มันมีประโยชน์อย่างมากอีกอย่างหนึ่ง: ถ้าสักวันเราทุกคนต้องการเปลี่ยนเป็นภาษาใหม่สมมุติ - เรียกมันว่า "สกาล่า" - เราแค่ต้องเขียนหนึ่งสกาล่า -> คอมไพเลอร์ bytecode แทนที่จะเป็นหลายรหัสสกาล่า -> คอมไพเลอร์ เป็นโบนัสเราได้รับการเพิ่มประสิทธิภาพเฉพาะแพลตฟอร์ม JVM ทั้งหมดฟรี
BlueRaja - Danny Pflughoeft

8
บางสิ่งยังคงเป็นไปไม่ได้ในรหัส JVM เช่นการเพิ่มประสิทธิภาพการโทรหาง ฉันจำได้ว่าสิ่งนี้ประนีประนอมอย่างมากกับภาษาที่ใช้งานได้ซึ่งรวมเข้ากับ JVM
JDługosz

8
@ JDługoszถูกต้อง: JVM โชคไม่ดีที่มีข้อ จำกัด / สำนวนการออกแบบที่ในขณะที่พวกเขาอาจจะเป็นธรรมชาติที่สมบูรณ์แบบถ้าคุณมาจากภาษาที่จำเป็นสามารถกลายเป็นอุปสรรคเทียมหากคุณต้องการเขียนคอมไพเลอร์สำหรับภาษาที่ทำงานพื้นฐาน ต่าง ฉันจึงพิจารณา LLVM ว่าเป็นเป้าหมายที่ดีกว่าตราบใดที่การใช้งานภาษาในอนาคตมีความกังวล - มันมีข้อ จำกัด เช่นกัน แต่พวกมันมากหรือน้อยตรงกับข้อ จำกัด ที่ตัวประมวลผลในปัจจุบัน (และมีแนวโน้มในอนาคต)
leftaroundabout

27

การเป็นตัวแทนระดับกลางของประเภทต่างๆนั้นมีอยู่ทั่วไปมากขึ้นในการออกแบบคอมไพเลอร์ / รันไทม์ด้วยเหตุผลบางประการ

ในกรณีของ Java เหตุผลอันดับหนึ่งในตอนแรกอาจเป็นเรื่องการพกพา : Java ถูกวางตลาดอย่างหนักในตอนแรกว่า "Write Once, Run Anywhere" ในขณะที่คุณสามารถบรรลุสิ่งนี้ได้โดยการแจกจ่ายซอร์สโค้ดและใช้คอมไพเลอร์ต่าง ๆ เพื่อกำหนดเป้าหมายแพลตฟอร์มที่แตกต่างกัน

  • คอมไพเลอร์เป็นเครื่องมือที่ซับซ้อนที่ต้องเข้าใจไวยากรณ์ความสะดวกสบายทั้งหมดของภาษา bytecode อาจเป็นภาษาที่ง่ายกว่าเพราะมันใกล้เคียงกับโค้ดที่รันด้วยเครื่องมากกว่าซอร์สที่มนุษย์สามารถอ่านได้ หมายความว่า:
    • การรวบรวมอาจช้าเมื่อเทียบกับการดำเนินการ bytecode
    • คอมไพเลอร์ที่กำหนดเป้าหมายแพลตฟอร์มที่แตกต่างกันอาจทำให้เกิดพฤติกรรมที่แตกต่างหรือไม่สอดคล้องกับการเปลี่ยนแปลงภาษา
    • การสร้างคอมไพเลอร์สำหรับแพลตฟอร์มใหม่นั้นหนักกว่าการสร้าง VM (หรือ bytecode-to-native คอมไพเลอร์) สำหรับแพลตฟอร์มนั้น
  • การแจกจ่ายซอร์สโค้ดนั้นไม่เป็นที่ต้องการเสมอไป bytecode เสนอการป้องกันบางอย่างกับวิศวกรรมย้อนกลับ (แม้ว่ามันจะยังง่ายต่อการถอดรหัสถ้าไม่ได้ตั้งใจ)

ข้อดีอื่น ๆ ของการเป็นตัวแทนระดับกลาง ได้แก่ :

  • การทำให้เกิดประโยชน์สูงสุดซึ่งรูปแบบสามารถถูกระบุในไบต์และรวบรวมลงเพื่อเทียบเท่าได้เร็วขึ้นหรือแม้กระทั่งการเพิ่มประสิทธิภาพสำหรับกรณีพิเศษในขณะที่โปรแกรมทำงาน (ใช้ "JIT" หรือ "Just In Time" คอมไพเลอร์)
  • ความสามารถในการทำงานร่วมกันระหว่างหลายภาษาใน VM เดียวกัน สิ่งนี้ได้รับความนิยมจาก JVM (เช่น Scala) และเป็นเป้าหมายที่ชัดเจนของ. net framework

1
Java ยังมุ่งเน้นไปที่ระบบการฝัง ในระบบดังกล่าวฮาร์ดแวร์มีข้อ จำกัด หลายประการของหน่วยความจำและซีพียู
Laiv

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

@ Sher10ck ใช่เป็นไปได้อย่างสมบูรณ์แบบที่ AFAIK จะเขียนคอมไพเลอร์ที่แปลง JVM bytecode เป็นคำสั่งเครื่องสำหรับสถาปัตยกรรมเฉพาะ แต่มันจะสมเหตุสมผลถ้าปรับปรุงประสิทธิภาพเพียงพอที่จะเกินดุลทั้งความพยายามพิเศษสำหรับผู้จัดจำหน่ายหรือเวลาพิเศษที่จะใช้งานครั้งแรกสำหรับผู้ใช้ ระบบฝังตัวที่ใช้พลังงานต่ำอาจได้รับประโยชน์ พีซีที่ทันสมัยดาวน์โหลดและเรียกใช้โปรแกรมที่แตกต่างกันอาจจะดีกว่าด้วย JIT ที่ได้รับการปรับ ฉันคิดว่า Android ไปที่ใดที่หนึ่งในทิศทางนี้ แต่ไม่ทราบรายละเอียด
IMSoP

8

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

ชัดเจนคำตอบที่นี่คือ Java โดยการออกแบบไม่คิดว่ามันรู้ว่าเครื่องเป็นที่รหัสของคุณจะทำงาน; มันอาจเป็นเดสก์ท็อป, ซุปเปอร์คอมพิวเตอร์, โทรศัพท์, หรืออะไรก็ได้ในระหว่างและหลังจากนั้น Java ออกจากพื้นที่สำหรับคอมไพเลอร์ JVM ท้องถิ่นเพื่อทำสิ่งนั้น นอกเหนือจากการเพิ่มความสามารถในการพกพาโค้ดของคุณสิ่งนี้มีประโยชน์อย่างมากในการอนุญาตให้คอมไพเลอร์ทำสิ่งต่าง ๆ เช่นใช้ประโยชน์จากการปรับแต่งเฉพาะเครื่องหากมีอยู่หรือยังคงสร้างรหัสการทำงานอย่างน้อยถ้าไม่มี สิ่งต่างๆเช่นคำแนะนำSSEหรือการเร่งความเร็วฮาร์ดแวร์สามารถใช้ได้กับเครื่องที่รองรับเท่านั้น

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

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

โปรดทราบว่าฉันไม่ได้กล่าวถึงการดำเนินการที่รวดเร็ว ทั้งซอร์สโค้ดและรหัสไบต์นั้นสามารถรวบรวมได้ในเครื่องจริงหรือในทางทฤษฎี

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


8

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

คอมไพเลอร์โดยทั่วไป

ลองพิจารณาคำถามทั่วไปก่อน: ทำไมคอมไพเลอร์จะใช้การเป็นตัวแทนขั้นกลางในกระบวนการรวบรวมซอร์สโค้ดเพื่อใช้กับโปรเซสเซอร์บางตัว

การลดความซับซ้อน

คำตอบเดียวนั้นค่อนข้างง่าย: มันแปลงปัญหา O (N * M) เป็นปัญหา O (N + M)

หากเราได้รับภาษาต้นฉบับ N ภาษาและเป้าหมาย M และคอมไพเลอร์แต่ละรายการมีความเป็นอิสระโดยสมบูรณ์เราจำเป็นต้องใช้โปรแกรมแปลภาษา N * M เพื่อแปลภาษาต้นฉบับทั้งหมดเหล่านั้นเป็นเป้าหมายทั้งหมด (โดยที่ "เป้าหมาย" เป็นสิ่งที่รวมกันของ โปรเซสเซอร์และระบบปฏิบัติการ)

อย่างไรก็ตามหากคอมไพเลอร์เหล่านั้นเห็นด้วยกับการเป็นตัวแทนระดับกลางทั่วไปเราสามารถมีส่วนหน้า N คอมไพเลอร์ที่แปลภาษาต้นฉบับเป็นตัวแทนระดับกลางและคอมไพเลอร์ M กลับด้านท้ายที่แปลการเป็นตัวแทนระดับกลางเป็นสิ่งที่เหมาะสมสำหรับเป้าหมายเฉพาะ

การแบ่งส่วนปัญหา

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

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

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

รูปแบบการกระจาย

ในกรณีที่ Java เพิ่มสิ่งใหม่ในแง่นี้มันอยู่ในรูปแบบการกระจาย โดยเฉพาะอย่างยิ่งถึงแม้ว่าคอมไพเลอร์จะถูกแยกเป็นส่วนหน้าและส่วนหลังภายในเป็นเวลานาน แต่โดยทั่วไปแล้วพวกมันจะถูกแจกจ่ายเป็นผลิตภัณฑ์ชิ้นเดียว ตัวอย่างเช่นหากคุณซื้อคอมไพเลอร์ Microsoft C ภายในจะมี "C1" และ "C2" ซึ่งเป็น front-end และ back-end ตามลำดับ - แต่สิ่งที่คุณซื้อคือ "Microsoft C" ที่รวมทั้ง ชิ้น (พร้อมกับ "ไดรเวอร์คอมไพเลอร์" ที่ประสานการทำงานระหว่างสอง) แม้ว่าคอมไพเลอร์จะถูกสร้างขึ้นเป็นสองชิ้น แต่สำหรับนักพัฒนาทั่วไปที่ใช้คอมไพเลอร์มันเป็นเพียงสิ่งเดียวที่แปลจากซอร์สโค้ดเป็นโค้ดออบเจ็กต์โดยไม่มีสิ่งใดปรากฏขึ้นระหว่างนั้น

Java แทนจำหน่าย front-end ใน Java Development Kit และ back-end ใน Java Virtual Machine ผู้ใช้ Java ทุกคนมีคอมไพเลอร์แบ็คเอนด์เพื่อกำหนดเป้าหมายสิ่งที่ระบบที่เขาใช้ ผู้พัฒนา Java แจกจ่ายรหัสในรูปแบบกลางดังนั้นเมื่อผู้ใช้โหลด JVM ทำสิ่งที่จำเป็นในการเรียกใช้งานบนเครื่องของตน

ทำนอง

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

รหัส Java byte

รหัส Java byte ค่อนข้างคล้ายกับรหัส P มันเป็นคำแนะนำพื้นฐานสำหรับเครื่องที่ค่อนข้างง่าย เครื่องดังกล่าวมีจุดประสงค์เพื่อให้เป็นนามธรรมของเครื่องที่มีอยู่ดังนั้นจึงค่อนข้างง่ายที่จะแปลอย่างรวดเร็วไปยังเป้าหมายที่เฉพาะเจาะจง ความง่ายในการแปลมีความสำคัญในช่วงต้นเพราะเจตนาดั้งเดิมคือการตีความรหัสไบต์เช่นเดียวกับระบบ P-System ได้ทำ (และใช่นั่นคือวิธีการใช้งานในช่วงต้น)

จุดแข็ง

โค้ด Java byte นั้นง่ายสำหรับคอมไพเลอร์ส่วนหน้าในการสร้าง หาก (ตัวอย่าง) คุณมีต้นไม้ที่ค่อนข้างปกติที่ใช้แทนนิพจน์โดยปกติแล้วมันค่อนข้างง่ายที่จะสำรวจต้นไม้และสร้างรหัสโดยตรงจากสิ่งที่คุณพบในแต่ละโหนด

รหัส Java byte ค่อนข้างกะทัดรัด - ในกรณีส่วนใหญ่มีขนาดกะทัดรัดกว่าซอร์สโค้ดหรือรหัสเครื่องสำหรับโปรเซสเซอร์ทั่วไปส่วนใหญ่ (และโดยเฉพาะอย่างยิ่งสำหรับโปรเซสเซอร์ RISC ส่วนใหญ่เช่น SPARC ที่ Sun ขายเมื่อออกแบบ Java) นี่เป็นสิ่งสำคัญอย่างยิ่งในขณะนี้เพราะจุดประสงค์หลักประการหนึ่งของจาวาคือเพื่อสนับสนุนแอปเพล็ - รหัสที่ฝังอยู่ในหน้าเว็บที่จะดาวน์โหลดก่อนการประหารชีวิต - ในเวลาที่คนส่วนใหญ่เข้าถึงเราผ่านโมเด็มผ่านสายโทรศัพท์ประมาณ 28.8 กิโลบิตต่อวินาที (แน่นอนว่ายังมีคนไม่กี่คนที่ใช้โมเด็มที่เก่ากว่าและช้ากว่า)

จุดอ่อน

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

ยกตัวอย่างเช่นมันเป็นประจำรักที่ถ้าคุณอยากที่จะเพิ่มประสิทธิภาพรหัสไบต์ Java คุณพื้นทำวิศวกรรมย้อนกลับบางอย่างที่จะแปลให้ถอยหลังจากเครื่องรหัสเช่นการแสดงและเปิดให้กลับเข้ามาในคำแนะนำ SSA (หรือบางสิ่งบางอย่างที่คล้ายกัน) 2 จากนั้นคุณปรับเปลี่ยนคำแนะนำ SSA เพื่อเพิ่มประสิทธิภาพของคุณจากนั้นแปลจากสิ่งนั้นเป็นสิ่งที่กำหนดเป้าหมายสถาปัตยกรรมที่คุณสนใจ แม้จะมีกระบวนการที่ค่อนข้างซับซ้อน แต่แนวคิดบางอย่างที่ต่างไปจาก Java นั้นยากพอที่จะบอกได้ว่าเป็นการยากที่จะแปลจากภาษาต้นฉบับบางภาษาไปเป็นรหัสเครื่องที่ทำงาน (แม้จะใกล้เคียง) อย่างเหมาะสมที่สุดบนเครื่องทั่วไปส่วนใหญ่

สรุป

หากคุณถามว่าทำไมต้องใช้การเป็นตัวแทนระดับกลางโดยทั่วไปปัจจัยหลักสองประการคือ:

  1. ลดปัญหา O (N * M) เป็นปัญหา O (N + M) และ
  2. แยกปัญหาออกเป็นส่วนที่จัดการได้มากขึ้น

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

  1. กระชับเป็นตัวแทน
  2. รวดเร็วและง่ายต่อการถอดรหัสและดำเนินการ
  3. รวดเร็วและง่ายต่อการใช้งานบนเครื่องทั่วไปส่วนใหญ่

ความสามารถในการแสดงหลายภาษาหรือดำเนินการอย่างเหมาะสมกับเป้าหมายที่หลากหลายนั้นมีความสำคัญน้อยกว่ามาก


  1. เหตุใดระบบ P จึงถูกลืมส่วนใหญ่? ส่วนใหญ่เป็นสถานการณ์การกำหนดราคา P-system ขายค่อนข้างดีใน Apple II ของ Commodore SuperPets ฯลฯ เมื่อ IBM PC ออกมา P-system เป็นระบบปฏิบัติการที่รองรับ แต่ MS-DOS ราคาถูกกว่า มีโปรแกรมเพิ่มเติมให้ใช้อย่างรวดเร็วเนื่องจากเป็นสิ่งที่ Microsoft และ IBM (อื่น ๆ ) เขียนไว้
  2. ตัวอย่างเช่นนี่คือการทำงานของSoot

ใกล้เคียงกับเว็บแอปเพล็ต: ความตั้งใจดั้งเดิมคือการแจกจ่ายรหัสไปยังเครื่องใช้ (กล่องรับสัญญาณ ... ) ในลักษณะเดียวกับที่ RPC กระจายการเรียกใช้ฟังก์ชันและ CORBA กระจายวัตถุ
ninjalj

2
นี่เป็นคำตอบที่ยอดเยี่ยมและความเข้าใจอย่างถ่องแท้เกี่ยวกับการเป็นตัวแทนระดับกลางที่แตกต่างกันทำให้การแลกเปลี่ยนแตกต่างกัน :)
IMSoP

@ninjalj: นั่นมันโอ๊กจริงๆ เมื่อถึงเวลาที่ปรับเปลี่ยนเป็น Java ฉันเชื่อว่าความคิด set top box (และที่คล้ายกัน) ได้ถูกระงับ (แม้ว่าฉันจะเป็นคนแรกที่ยอมรับว่ามีข้อโต้แย้งที่ยุติธรรมที่จะทำให้ Oak และ Java เป็นสิ่งเดียวกัน)
Jerry Coffin

@TobySpeight: ใช่การแสดงออกน่าจะเหมาะสมกว่านั้น ขอบคุณ
Jerry Coffin

0

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

นอกจากนี้ยังช่วยป้องกันรหัสต้นฉบับที่มีลิขสิทธิ์ได้ง่ายขึ้น


2
bytecode ของ Java (และ. NET) นั้นง่ายต่อการเปลี่ยนกลับไปเป็นแหล่งที่อ่านได้ง่ายที่สมเหตุสมผลซึ่งมีผลิตภัณฑ์ที่ใช้ในการยั่วชื่อและบางครั้งข้อมูลอื่น ๆ ที่จะทำให้สิ่งนี้ยากขึ้น อาจตั้งค่าเป็น bytecode สำหรับเว็บเบราว์เซอร์
LnxPrgr3

0

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


0

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

ต่อมาเมื่อเห็นได้ชัดว่าประสิทธิภาพการทำงานของการตีความ JVM ยังคงถูกดูดกลืนผู้คนลงทุนเพื่อพยายามสร้างคอมไพเลอร์ทันเวลาที่มีประสิทธิภาพดี นี่เป็นการปิดช่องว่างของภาษาที่เร็วกว่าเช่น C และ C ++ (บางประเด็นเกี่ยวกับความเร็วของ Java ยังคงอยู่ดังนั้นคุณอาจจะไม่ได้รับสภาพแวดล้อมของ Java ที่ทำงานได้ดีเท่ากับรหัสภาษา C ที่เขียนขึ้น)

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


ผู้ลงคะแนนเสียงโปรดอธิบายว่าทำไม ?
cmaster

-5

รหัสแหล่งที่มาของข้อความเป็นโครงสร้างที่ตั้งใจให้มนุษย์อ่านและแก้ไขได้ง่าย

รหัสไบต์เป็นโครงสร้างที่ตั้งใจให้ง่ายต่อการอ่านและดำเนินการโดยเครื่อง

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

ฉันสังเกตเห็นว่ายังไม่มีตัวอย่างใด ๆ ตัวอย่าง Silly Pseudo:

//Source code
i += 1 + 5 * 2 + x;

// Byte code
i += 11, i += x
____

//Source code
i = sin(1);

// Byte code
i = 0.8414709848
_____

//Source code
i = sin(x)^2+cos(x)^2;

// Byte code (actually that one isn't true)
i = 1

แน่นอนว่าโค้ดไบต์ไม่ได้เกี่ยวกับการปรับให้เหมาะสมเท่านั้น ส่วนใหญ่เป็นเรื่องเกี่ยวกับความสามารถในการรันโค้ดโดยไม่ต้องสนใจกฎที่ซับซ้อนเช่นการตรวจสอบว่าคลาสมีสมาชิกชื่อ "foo" อยู่ที่ไหนสักแห่งในไฟล์เมื่อเมธอดอ้างถึง "foo"


2
โค้ด "ไบต์" ของไบต์เหล่านั้นสามารถอ่านได้โดยมนุษย์ นั่นไม่ใช่รหัสไบต์เลย นี่เป็นสิ่งที่ทำให้เข้าใจผิดและไม่ได้ตอบคำถามที่ถาม
Wildcard

@Wildcard คุณอาจพลาดฟอรัมนี้อ่านโดยมนุษย์ นั่นเป็นเหตุผลที่ฉันใส่เนื้อหาในรูปแบบที่มนุษย์อ่านได้ ระบุว่าฟอรั่มเป็นเรื่องเกี่ยวกับวิศวกรรมซอฟต์แวร์การขอให้ผู้อ่านเข้าใจแนวคิดเรื่องนามธรรมอย่างง่ายไม่ได้ถามอะไรมากมาย
ปีเตอร์

แบบฟอร์มที่มนุษย์อ่านได้คือซอร์สโค้ดไม่ใช่รหัสไบต์ คุณกำลังแสดงซอร์สโค้ดด้วยนิพจน์ที่คำนวณล่วงหน้า ไม่ใช่โค้ดไบต์ และฉันก็ไม่พลาดว่านี่เป็นฟอรัมที่มนุษย์สามารถอ่านได้: คุณเป็นคนที่วิพากษ์วิจารณ์ผู้ตอบคำถามคนอื่นโดยไม่รวมตัวอย่างของรหัสไบต์ไม่ใช่ฉัน ดังนั้นคุณพูดว่า "ผมสังเกตเห็นมีไม่ได้ตัวอย่างใด ๆ เลย" แล้วดำเนินการต่อไปให้ที่ไม่ใช่ -examples ที่ไม่ได้แสดงให้เห็นถึงรหัสไบต์ที่ทั้งหมด และสิ่งนี้ยังไม่สามารถตอบคำถามได้ทั้งหมด อ่านคำถามอีกครั้ง
Wildcard
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.