คำนำ
ในบรรดานักพัฒนา Java การครอบครองทรัพยากรสูงของสตริงมักจะเป็นประเด็นร้อนแรง
มาพูดคุยกันในเชิงลึกว่าทำไมจึงมีทรัพยากรสูง
ใน Java วัตถุสตริงไม่เปลี่ยนรูปหมายความว่าเมื่อมันถูกสร้างขึ้นคุณจะไม่สามารถเปลี่ยนได้อีกต่อไป ดังนั้นเมื่อเราประกบสายเราสร้างสตริงใหม่และอันเก่าจะถูกทำเครื่องหมายโดยนักสะสมขยะ
หากเราประมวลผลหลายล้านสตริงเราจะสร้างสตริงเพิ่มเติมหลายล้านสายเพื่อประมวลผลโดยนักสะสมขยะ
ในบทช่วยสอนส่วนใหญ่คุณอาจเห็นว่าการใช้ + สัญญาณไปยังสายประกบจะสร้างหลายสตริงส่งผลให้ประสิทธิภาพไม่ดี ขอแนะนำให้ใช้ StringBuffer/StringBuilder เพื่อ Splice
แต่นี่เป็นกรณีจริงเหรอ?
บทความนี้ได้ทำการทดลองต่อไปนี้ใน JDK8:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {string result = ""; ผลลัพธ์ += "ข้อมูลเพิ่มเติม"; System.out.println (ผลลัพธ์); -ถอดรหัสผ่าน Javap -C เพื่อรับ:
รหัส: 0: aload_0 // push 'this' ไปที่สแต็ก 1: invokespecial #1 // เรียกใช้คอนสตรัคเตอร์คลาส Object // pop 'ref' จากสแต็ก 4: return // กลับจากคอนสตรัคเตอร์สาธารณะคงที่ รหัส: 0: LDC #2 // โหลดค่าคงที่ #2 บนสแต็ก 2: store_1 // สร้าง var ท้องถิ่นจากสแต็ก (ป๊อป #2) 3: ใหม่ #3 // ผลักดันสตริงใหม่ Ref บนสแต็ก 6: DUP // ค่าที่ซ้ำกันที่ด้านบนของสแต็ค 7: Invokespecial #4 // invokevirtual #5 // revoke method stringbuilder.append () // pop obj อ้างอิง + พารามิเตอร์ // push result (stringbuilder ref) 14: ldc #6 // push "ข้อมูลเพิ่มเติม" บนสแต็ก 16: invokevirtual #5 // reckoke stringbuilder.append // pop สองครั้ง 22: store_1 // สร้าง var ท้องถิ่นจากสแต็ก (ป๊อป #6) 23: getstatic #8 // ระบบค่าพุช. เอาท์: printstream 26: aload_1 // push ตัวแปรท้องถิ่นที่มี #6 27: invokevirtual #9 // วิธีการ printstream.println () // pop สองครั้ง
คุณจะเห็นว่าคอมไพเลอร์ Java เพิ่มประสิทธิภาพไบต์ที่สร้างขึ้นสร้าง StringBuilder โดยอัตโนมัติและดำเนินการต่อไป
เนื่องจากหมวดย่อยของสตริงสุดท้ายเป็นที่รู้จักกันแล้วในเวลาคอมไพล์คอมไพเลอร์ Java จะทำการปรับให้เหมาะสมที่สุดในกรณีนี้ การเพิ่มประสิทธิภาพนี้เรียกว่าการเพิ่มประสิทธิภาพการต่อการต่อเนื่องของสตริงแบบคงที่และเปิดใช้งานตั้งแต่ JDK5
นั่นหมายความว่าหลังจาก JDK5 เราไม่จำเป็นต้องสร้าง StringBuilder ด้วยตนเองอีกต่อไปและเราสามารถบรรลุประสิทธิภาพเดียวกันผ่านเครื่องหมาย +?
ลองใช้สตริงประกบกันแบบไดนามิก:
สตริงการประกบแบบไดนามิกหมายถึงสตริงย่อยที่รู้จักกันในรันไทม์เท่านั้น ตัวอย่างเช่นการเพิ่มสตริงลงในลูป:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {string result = ""; สำหรับ (int i = 0; i <10; i ++) {ผลลัพธ์+= "ข้อมูลเพิ่มเติมบางอย่าง"; } system.out.println (ผลลัพธ์); -ยังสลายตัวด้วย:
รหัส: 0: aload_0 // push 'this' ไปที่สแต็ก 1: invokespecial #1 // เรียกใช้คอนสตรัคเตอร์คลาส Object // pop 'ref' จากสแต็ก 4: return // กลับจากคอนสตรัคเตอร์สาธารณะคงที่ รหัส: 0: LDC #2 // โหลดค่าคงที่ #2 บนสแต็ก 2: store_1 // สร้าง var ท้องถิ่นจากสแต็ก, ป๊อป #2 3: iconst_0 // push value 0 บนสแต็ก 4: istore_2 // ค่าป๊อปและเก็บไว้ใน local var 5: iload_2 // push local var 2 ldc2_w #3 // กดคงที่ 10e6 ไปที่สแต็ค 10: dcmpg // เปรียบเทียบสองคู่ที่ด้านบนของสแต็ก // ป๊อปสองครั้ง, กดผลลัพธ์: -1, 0 หรือ 1 11: ifge 40 // ถ้าค่าบนสแต็กสูงกว่า / / / / / / / / / / / / / / / / สแต็ค 18: Invokespecial #6 // เรียกใช้ StringBuilder Constructor // Pop Object Reference 21: Aload_1 // PUSH LOCAL VAR 1 (สตริงว่าง) // ไปที่สแต็ก 22: invokeVirtual #7 // revoke Stringbuilder.Append // pop obj ref + param StringBuilder.Append // pop obj ref + param, push result 30: invokevirtual #9 // revoke stringbuilder.toString // การอ้างอิงวัตถุป๊อป 33: store_1 // สร้าง var ท้องถิ่นจากสแต็ก (ป๊อป) 34: IINC 2, 1 // ตัวแปร aload_1 // push local var 1 (สตริงผลลัพธ์) 44: invokevirtual #11 // revoke method printstream.println () // pop สองครั้ง (วัตถุอ้างอิงวัตถุ + พารามิเตอร์) 47: return // return void จากวิธีการ
คุณจะเห็นว่า Stringbuilder เป็นของใหม่ที่ 14 แต่ที่ 37, goto 5 ระหว่างการวนรอบการเพิ่มประสิทธิภาพไม่ประสบความสำเร็จและผู้สร้างสตริงใหม่ถูกสร้างขึ้นอย่างต่อเนื่อง
ดังนั้นรหัสข้างต้นจึงคล้ายกัน:
String result = ""; สำหรับ (int i = 0; i <10; i ++) {stringBuilder tmp = new StringBuilder (); tmp.append (ผลลัพธ์); tmp.append ("ข้อมูลเพิ่มเติม"); result = tmp.toString ();} system.out.println (ผลลัพธ์);คุณจะเห็นได้ว่า Stringbuilders ใหม่จะถูกสร้างขึ้นอย่างต่อเนื่องและผ่าน toString StringBuilder ดั้งเดิมจะไม่ถูกอ้างอิงอีกต่อไปเป็นขยะและยังเพิ่มต้นทุน GC
ดังนั้นในการใช้งานจริงเมื่อคุณไม่สามารถแยกแยะได้ว่าสตริงนั้นคงที่หรือแบบไดนามิกให้ใช้ StringBuilder
อ้างอิง:
http://www.pellegrino.link/2015/08/22/string-concatenation-with-java-8.html
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com