การรวมวัตถุเป็นเทคนิคที่เลิกใช้หรือไม่?


62

ฉันคุ้นเคยกับแนวคิดของการรวมวัตถุและฉันพยายามที่จะใช้มันให้มากที่สุด

นอกจากนี้ฉันมักจะคิดว่าการรวมวัตถุเป็นบรรทัดฐานมาตรฐานที่ฉันสังเกตเห็นว่า Java เองรวมถึงกรอบงานอื่น ๆ ที่ใช้ร่วมกันมากที่สุด

เมื่อเร็ว ๆ นี้แม้ว่าฉันจะอ่านอะไรบางอย่างที่เป็นของใหม่

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

ฉันอ่านสิ่งนี้ในหนังสือ: Java Concurrency in Practice

ตอนนี้ฉันเริ่มคิดว่าถ้าฉันเข้าใจบางสิ่งบางอย่างที่นี่ตั้งแต่ส่วนแรกของหนังสือแนะนำให้ใช้Executorsซ้ำนั้นThreadแทนที่จะสร้างอินสแตนซ์ใหม่

การรวมวัตถุได้กลายเป็นที่นิยมในปัจจุบัน?

คำตอบ:


72

มันเลิกใช้เป็นเทคนิคทั่วไปเพราะ - ตามที่คุณสังเกตเห็น - การสร้างและการทำลายวัตถุที่มีอายุสั้นต่อ se (เช่นการจัดสรรหน่วยความจำและ GC) มีราคาถูกมากใน JVM สมัยใหม่ ดังนั้นการใช้ออบเจ็กต์ที่เขียนด้วยมือสำหรับออบเจ็กต์ที่ทำงานด้วยมือของคุณน่าจะช้ากว่าซับซ้อนกว่าและเกิดข้อผิดพลาดมากกว่าธรรมดาnew*

มันยังคงมีการใช้งานแม้ว่าสำหรับวัตถุพิเศษที่การสร้างค่อนข้างแพงเช่นการเชื่อมต่อ DB / เครือข่ายเธรด ฯลฯ

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


1
ดังนั้นเราจะตัดสินใจได้อย่างไรว่าการสร้างอินสแตนซ์ของวัตถุมีราคาแพงเกินไป?
user10326

3
หากวัตถุนั้นใช้ทรัพยากรระบบปฏิบัติการ (เธรด, I / O, หน่วยความจำที่ใช้ร่วมกัน ฯลฯ )
kevin cline

13
@ user10326 โดยการวัด :-) หากการสร้างวัตถุของคุณใช้เวลา looooong และ / หรือเกี่ยวข้องกับทรัพยากรที่ไม่ใช่หน่วยความจำพิเศษบางอย่างคุณอาจพิจารณาการรวมกำไร
PéterTörök

8
@ user10326, IMO ในกว่า 95% ของกรณีเกณฑ์ข้างต้นทำให้ง่ายต่อการตัดสินใจล่วงหน้าว่าคุณต้องการกลุ่มวัตถุ (ยิ่งกว่านั้นในเกือบทุกกรณีที่ต้องการพูลคุณมักจะใช้ไลบรารี่ / เฟรมเวิร์กที่มีอยู่ซึ่งน่าจะมี Object Pool ที่นำมาใช้แล้วสำหรับคุณ) ส่วนที่เหลือมันยังง่ายต่อการซ่อนการสร้างวัตถุเช่น โรงงานซึ่งสามารถนำมาใช้ใหม่ได้ในภายหลังตามวิธีที่คุณเห็นว่าเหมาะสม
PéterTörök

2
จุดสำคัญมากที่ทำโดย @Peter Torok: เฟรมเวิร์กและไลบรารีจำนวนมากใช้การรวมกำไรสำหรับคุณเสมอให้แน่ใจว่าคุณยังไม่ได้ใช้ไลบรารีที่รวบรวมไว้ก่อนที่จะนำไปใช้เอง
hromanko

36

คำตอบสำหรับคำถามที่เป็นรูปธรรม: 'การรวมวัตถุเป็นเทคนิคที่เลิกใช้หรือไม่' คือ:

ไม่ Object Objecting ถูกใช้อย่างแพร่หลายในบางสถานที่เช่นการรวมเธรดการรวมการเชื่อมต่อฐานข้อมูลเป็นต้น

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

กฎคือ:

การเพิ่มประสิทธิภาพก่อนวัยเป็นความชั่วร้าย !!!

แต่เมื่อใดที่การเพิ่มประสิทธิภาพที่กำหนดไว้ก่อนกำหนด?

การเพิ่มประสิทธิภาพก่อนวัยอันควรมีการเพิ่มประสิทธิภาพใด ๆทำก่อนที่คุณจะได้ค้นพบคอขวดผ่านการตรวจสอบอย่างละเอียดโปรไฟล์


2
จริง OP กล่าวว่า "ฉันพยายามใช้ให้บ่อยที่สุดเท่าที่จะทำได้" - นี่คือปัญหา IMO
nerdytenor

@ บอริสดังนั้นตามประโยคที่สองของคุณเราไม่ควรคัดค้านการเชื่อมต่อและเธรดพูล db จนกว่าเราจะเปิดเผยว่าเป็นคอขวดผ่านการทำโปรไฟล์?
Pacerier

1
@Pac บางผล profiling ไม่จำเป็นต้องคงอีกวัด :-)
เดวิดวัว

9

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


1
และฉันจะเพิ่มว่ามันเป็นความคิดที่ดีที่จะหลีกเลี่ยง GC เมื่อใดก็ตามที่วัตถุมีอายุยืนยาวพอที่พวกมันจะย้ายไปอยู่ในรุ่นที่เก่ากว่า
Zan Lynx

8

วัด

ขึ้นอยู่กับกรณีการใช้งานของคุณขนาดของวัตถุ JVM ของคุณตัวเลือก JVM ของคุณสิ่งที่คุณเปิดใช้งาน GC และโฮสต์ทั้งหมดของปัจจัยอื่น ๆ

ในระยะสั้น: วัดก่อนและวัดหลังจาก สมมติว่าคุณกำลังใช้เฟรมเวิร์กรวมกำไรวัตถุ (เช่นจาก Apache) แล้วมันไม่ควรเจ็บปวดเกินไปที่จะสลับระหว่างการใช้งาน

เคล็ดลับการทดสอบประสิทธิภาพพิเศษ - ให้ JVM อุ่นเครื่องก่อนรันการทดสอบบน JVM ที่กำลังทำงานอยู่หลายครั้งมันสามารถทำงานแตกต่างกันได้


3
"ให้ JVM อุ่นเครื่องก่อน" - ฉันจำได้เมื่อสิ่งเดียวที่ต้อง "อุ่นเครื่อง" คือจอภาพ Oy ทุกสิ่งใหม่เก่าอีกครั้ง
kylben

สิ่งเดียวที่ฉันต้องเตรียมคือกาแฟ!
ไม่แยแส

@Marijn คุณจะปล่อยให้ "อุ่นเครื่อง" ได้อย่างไร?
Pacerier

ดู JMH Framework สำหรับคำอธิบายแบบเต็ม ( openjdk.java.net/projects/code-tools/jmh ) แต่โดยทั่วไปคุณต้องให้ JVM มีโอกาสที่จะ JIT รหัสของคุณรัน GC's ก่อนเกณฑ์มาตรฐานและอื่น ๆ
Martijn Verburg

8

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

ขึ้นอยู่กับบริบท


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

5

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


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

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