ผลกระทบของประสิทธิภาพการใช้งานอินสแตนซ์ใน Java


314

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

ตัวอย่างเช่นฉันมีคลาสฐานที่มี 10 คลาสย่อย ในฟังก์ชั่นเดียวที่ใช้คลาสพื้นฐานฉันจะตรวจสอบว่าคลาสเป็นอินสแตนซ์ของคลาสย่อยและดำเนินการตามปกติ

อีกวิธีหนึ่งที่ฉันคิดว่าการแก้มันคือการใช้จำนวนเต็ม "type id" ดั้งเดิมแทนและใช้ bitmask เพื่อแสดงหมวดหมู่ของคลาสย่อยและจากนั้นก็ทำการเปรียบเทียบรูปแบบบิตของ subclasses "type id" กับ a หน้ากากคงที่เป็นตัวแทนของหมวดหมู่

เป็นที่instanceofที่ดีที่สุดอย่างใดโดย JVM ที่จะได้เร็วขึ้นกว่าที่? ฉันต้องการติดกับ Java แต่ประสิทธิภาพของแอพมีความสำคัญอย่างยิ่ง มันจะเจ๋งถ้ามีคนที่เคยไปตามถนนนี้มาก่อนจะได้รับคำแนะนำ ฉันกำลัง nitpicking มากเกินไปหรือเน้นสิ่งผิดเพื่อเพิ่มประสิทธิภาพหรือไม่


81
ฉันคิดว่าประเด็นของคำถามคือการตั้งคำถามของแนวปฏิบัติ OO ที่ดีที่สุดและตรวจสอบประสิทธิภาพ
Dave L.

3
@Dave L. ปกติฉันจะเห็นด้วย แต่ OP กล่าวถึงว่าเขากำลังมองหาเทคนิคการเพิ่มประสิทธิภาพทั่วไปและเขาไม่แน่ใจว่าปัญหาของเขาเกี่ยวข้องกับ 'instanceof' หรือไม่ ฉันคิดว่ามันมีค่าอย่างน้อยพูดถึงการออกแบบที่ 'ถูกต้อง' เพื่อให้เขาสามารถสร้างตัวเลือกทั้งสอง
Outlaw Programmer

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

3
ประสิทธิภาพของอินสแตนซ์และการหล่อค่อนข้างดี ฉันโพสต์เวลาใน Java7 เกี่ยวกับวิธีการที่แตกต่างกันของปัญหาที่นี่: stackoverflow.com/questions/16320014/…
Wheezil

คำตอบ:


268

คอมไพเลอร์ JVM / JIC ที่ทันสมัยได้ลบประสิทธิภาพการทำงานของการดำเนินการ "ช้า" ส่วนใหญ่แบบดั้งเดิมซึ่งรวมถึงอินสแตนซ์ของการจัดการข้อยกเว้นการสะท้อนกลับ ฯลฯ

ดังที่ Donald Knuth เขียนว่า "เราควรลืมประสิทธิภาพเล็กน้อยพูดประมาณ 97% ของเวลา: การปรับให้เหมาะสมก่อนกำหนดเป็นรากของความชั่วร้ายทั้งหมด" ประสิทธิภาพของอินสแตนซ์ของอาจจะไม่เป็นปัญหาดังนั้นอย่าเสียเวลาไปกับการแก้ปัญหาที่แปลกใหม่จนกว่าคุณจะแน่ใจว่าเป็นปัญหา


13
Modern JVM / JIC .. คุณช่วยกรุณาพูดถึงการเพิ่มประสิทธิภาพ Java รุ่นใดบ้าง
Ravisha

138
มักจะมีใครบางคนที่อ้างอิง Knuth เมื่อการแสดงเป็นหัวข้อ ... ลืมไปว่า Knuth ยังระบุไว้ (ในบทความเดียวกัน) "ในสาขาวิชาวิศวกรรมที่จัดตั้งขึ้นมีการปรับปรุง 12% ได้ง่ายไม่เคยถูกมองว่าเป็นขอบและฉันเชื่อว่ามุมมองเดียวกัน ควรเหนือกว่าในด้านวิศวกรรมซอฟต์แวร์ "เกือบทุกงานของเขาเกี่ยวกับประสิทธิภาพของอัลกอริธึมและเขาเขียนอัลกอริธึมในการประกอบเพื่อ Meh ...
kgadek

4
ที่นี่ แต่จะtry { ObjT o = (ObjT)object } catch (e) { no not one of these }ช้ากว่ากันไหม
peterk

35
หาก "object" เป็นตัวอย่างของ ObjT การคัดเลือกจะทำได้เร็วกว่าการทำอินสแตนซ์เพียงเล็กน้อย แต่ความแตกต่างที่พบในการทดสอบอย่างรวดเร็วของฉันคือ 10-20 มิลลิวินาทีมากกว่า 10,000,000 ครั้ง หาก "object" ไม่ใช่ ObjT การจับข้อยกเว้นนั้นช้ากว่า 3000x - มากกว่า 31,000ms เทียบกับ ~ 10ms สำหรับอินสแตนซ์ของ
Steve

19
อาร์กิวเมนต์ที่แข็งแกร่งเช่นนี้โดยไม่มี "การอ้างอิง" ไม่มีประโยชน์อย่างสมบูรณ์เพราะมีเพียงความเห็น
marcorossi

279

เข้าใกล้

ฉันเขียนโปรแกรมมาตรฐานเพื่อประเมินการใช้งานที่แตกต่างกัน:

  1. instanceof การใช้งาน (เป็นข้อมูลอ้างอิง)
  2. วัตถุปรับทิศทางผ่านคลาสนามธรรมและ@Overrideวิธีทดสอบ
  3. ใช้ชนิดการนำไปปฏิบัติ
  4. getClass() == _.class การดำเนินงาน

ฉันใช้jmhเพื่อรันเกณฑ์มาตรฐานด้วยการเรียก warmup 100 ครั้งการวนซ้ำ 1,000 ครั้งภายใต้การวัดและด้วย 10 ส้อม ดังนั้นแต่ละตัวเลือกจึงถูกวัดด้วย 10,000 ครั้งซึ่งใช้เวลา 12:18:57 น. ในการรันเกณฑ์มาตรฐานทั้งหมดบน MacBook Pro ของฉันกับ macOS 10.12.4 และ Java 1.8 มาตรฐานวัดเวลาเฉลี่ยของแต่ละตัวเลือก สำหรับรายละเอียดเพิ่มเติมโปรดดูที่การดำเนินงานของฉันบน GitHub

เพื่อความครบถ้วนสมบูรณ์: มีเป็นรุ่นก่อนหน้าของคำตอบนี้และมาตรฐานของฉัน

ผล

| การทำงาน | รันไทม์เป็นนาโนวินาทีต่อการดำเนินการ สัมพันธ์กับ instanceof |
| ------------ | ------------------------------------ - | ------------------------ |
| INSTANCEOF | 39,598 ± 0,022 ns / op | 100,00% |
| GETCLASS | 39,687 ± 0,021 ns / op | 100,22% |
| TYPE | 46,295 ± 0,026 ns / op | 116,91% |
| OO | 48,078 ± 0,026 ns / op | 121,42% |

TL; DR

ใน Java 1.8 instanceofเป็นวิธีที่เร็วที่สุดแม้ว่าgetClass()จะใกล้มาก


58
+0.(9)วิทยาศาสตร์!

16
+ อีก 0.1 จากฉัน: D
Tobias Reich

14
@TobiasReich +1.0(9)ดังนั้นเราจึงมี :)
พาเวล

9
ฉันไม่คิดว่ามาตรการนี้มีความหมายอะไรเลย การวัดรหัสใช้System.currentTimeMillis()ในการดำเนินการที่ไม่มากไปกว่าการเรียกใช้วิธีการเดียวซึ่งควรให้ความแม่นยำต่ำมาก ใช้เฟรมเวิร์กเปรียบเทียบเช่นJMHแทน!
Lii

6
หรือเพียงแค่กำหนดเวลาของการโทรทั้งพันล้านครั้งแทนที่จะเป็นการโทรต่อครั้ง
LegendLength

74

ฉันเพิ่งทำการทดสอบอย่างง่าย ๆ เพื่อดูว่าประสิทธิภาพของ instanceOf เปรียบเทียบกับการเรียก s.equals () แบบง่ายไปยังอ็อบเจกต์สตริงที่มีตัวอักษรเพียงตัวเดียว

ใน 10.000.000 ลูป instanceOf ให้ฉัน 63-96ms และสตริงเท่ากับให้ 106-230ms

ฉันใช้ java jvm 6

ดังนั้นในการทดสอบอย่างง่ายของฉันจะเร็วกว่าที่จะทำ instanceOf แทนที่จะเปรียบเทียบหนึ่งตัวอักษรสตริง

การใช้. Equals () ของ Integer แทนที่จะเป็นสตริงให้ผลลัพธ์แบบเดียวกันเมื่อฉันใช้ == ฉันเร็วกว่า instanceOf ภายใน 20ms (ใน 10.000.000 loop)


4
เป็นไปได้ไหมที่คุณจะโพสต์รหัสที่นี่? นั่นจะยอดเยี่ยม!
นักเล่นแร่แปรธาตุ

7
instanceOf เปรียบเทียบกับการจัดส่งฟังก์ชัน polymorphic อย่างไร
Chris

21
ทำไมคุณถึงเปรียบเทียบ instanceof กับ String.equals () หากคุณต้องการตรวจสอบประเภทที่คุณต้อง object.getClass (). เท่ากับ (SomeType.class)
marsbear

4
@marsbear equals()จะไม่ตัดมันเพราะคลาสย่อย isAssignableFrom()คุณจำเป็นต้อง
David Moles

1
@marsbear ใช่ แต่นั่นไม่ใช่การทดสอบที่ดีกว่าว่า OP ขออะไร
David Moles

20

รายการที่จะกำหนดผลกระทบต่อประสิทธิภาพคือ:

  1. จำนวนคลาสที่เป็นไปได้ซึ่งตัวดำเนินการ instanceof สามารถคืนค่าเป็นจริง
  2. การกระจายข้อมูลของคุณ - การดำเนินงานของอินสแตนซ์ส่วนใหญ่ได้รับการแก้ไขในครั้งแรกหรือครั้งที่สองหรือไม่? คุณจะต้องทำให้โอกาสในการกลับมาดำเนินการจริงก่อน
  3. สภาพแวดล้อมในการปรับใช้ การใช้งาน Sun Solaris VM นั้นแตกต่างจาก Windows JVM ของ Sun อย่างมาก Solaris จะทำงานในโหมด 'เซิร์ฟเวอร์' โดยค่าเริ่มต้นในขณะที่ Windows จะทำงานในโหมดไคลเอนต์ การเพิ่มประสิทธิภาพ JIT บน Solaris จะทำให้วิธีการเข้าถึงทั้งหมดสามารถเหมือนกัน

ฉันสร้างmicrobenchmark สำหรับสี่วิธีการที่แตกต่างกันของการจัดส่ง ผลลัพธ์จาก Solaris มีดังนี้โดยจำนวนที่น้อยกว่าจะเร็วกว่า:

InstanceOf 3156
class== 2925 
OO 3083 
Id 3067 

18

ตอบคำถามสุดท้ายของคุณ: หากไม่มี profiler บอกคุณว่าคุณใช้เวลาอย่างไร้สาระในกรณีของ: ใช่คุณกำลัง nitpicking

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

ในเวลาที่คอมไพเลอร์ปรับให้เหมาะสมที่สุดการคาดเดาของคุณเกี่ยวกับคอขวดจะมีความผิดอย่างสมบูรณ์

และด้วยจิตวิญญาณที่แท้จริงของคำตอบนี้ (ซึ่งฉันเชื่ออย่างสุดใจ): ฉันไม่รู้แน่ชัดว่าอินสแตนซ์ของและ == เกี่ยวข้องเมื่อ jit-compiler มีโอกาสเพิ่มประสิทธิภาพมัน

ฉันลืม: อย่าวัดระยะวิ่งครั้งแรก


1
แต่โปสเตอร์ดั้งเดิมที่กล่าวถึงการแสดงนั้นมีความสำคัญสำหรับแอปพลิเคชันนี้ดังนั้นจึงไม่มีเหตุผลที่จะเพิ่มประสิทธิภาพในช่วงต้นของสถานการณ์นั้น กล่าวอีกนัยหนึ่งคุณจะไม่เขียนเกม 3 มิติใน GWBasic และในที่สุดก็บอกว่าโอเคเรามาเริ่มที่จะเพิ่มประสิทธิภาพสิ่งนี้ขั้นแรกคือการย้ายไปที่ c ++
LegendLength

GWBasic อาจเป็นการเริ่มต้นที่ยอดเยี่ยมสำหรับเกม 3 มิติหากมีห้องสมุดที่เหมาะสม แต่นั่นนอกเหนือจาก (เนื่องจากเป็นข้อโต้แย้งเทียม): OP ไม่ได้ขอให้เขียนใหม่ทั้งหมดเป็นการเพิ่มประสิทธิภาพ มันเกี่ยวกับสิ่งก่อสร้างเดียวที่เราไม่รู้ด้วยซ้ำว่าผลกระทบนั้นสำคัญหรือไม่ (แม้ว่าจะมีวิธีการทำงานที่ดีกว่าในการคอมไพเลอร์เวอร์ชั่นปัจจุบัน ) ฉันยืนหยัดอยู่ข้างหลังc2.com/cgi/wiki?ProfileBeforeOptimizingและคำตอบของฉัน การเพิ่มประสิทธิภาพเบื้องต้นเป็นรากฐานของความชั่วร้ายทั้งหมด! มันทำให้การบำรุงรักษายากขึ้น - และการบำรุงรักษาเป็นสิ่งที่คุ้มค่าต่อการเพิ่มประสิทธิภาพ
Olaf Kock

15

ฉันมีคำถามเดียวกัน แต่เนื่องจากฉันไม่พบ 'ตัวชี้วัดประสิทธิภาพ' สำหรับกรณีการใช้งานที่คล้ายกับของฉันฉันได้ทำโค้ดตัวอย่างเพิ่มเติม บนฮาร์ดแวร์ของฉันและ Java 6 & 7 ความแตกต่างระหว่างอินสแตนซ์ของและสลับกับการทำซ้ำ 10mln คือ

for 10 child classes - instanceof: 1200ms vs switch: 470ms
for 5 child classes  - instanceof:  375ms vs switch: 204ms

ดังนั้นอินสแตนซ์ของช้าลงโดยเฉพาะอย่างยิ่งในงบ if-else-if จำนวนมากอย่างไรก็ตามความแตกต่างจะเล็กน้อยในการสมัครจริง

import java.util.Date;

public class InstanceOfVsEnum {

    public static int c1, c2, c3, c4, c5, c6, c7, c8, c9, cA;

    public static class Handler {
        public enum Type { Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, TypeA }
        protected Handler(Type type) { this.type = type; }
        public final Type type;

        public static void addHandlerInstanceOf(Handler h) {
            if( h instanceof H1) { c1++; }
            else if( h instanceof H2) { c2++; }
            else if( h instanceof H3) { c3++; }
            else if( h instanceof H4) { c4++; }
            else if( h instanceof H5) { c5++; }
            else if( h instanceof H6) { c6++; }
            else if( h instanceof H7) { c7++; }
            else if( h instanceof H8) { c8++; }
            else if( h instanceof H9) { c9++; }
            else if( h instanceof HA) { cA++; }
        }

        public static void addHandlerSwitch(Handler h) {
            switch( h.type ) {
                case Type1: c1++; break;
                case Type2: c2++; break;
                case Type3: c3++; break;
                case Type4: c4++; break;
                case Type5: c5++; break;
                case Type6: c6++; break;
                case Type7: c7++; break;
                case Type8: c8++; break;
                case Type9: c9++; break;
                case TypeA: cA++; break;
            }
        }
    }

    public static class H1 extends Handler { public H1() { super(Type.Type1); } }
    public static class H2 extends Handler { public H2() { super(Type.Type2); } }
    public static class H3 extends Handler { public H3() { super(Type.Type3); } }
    public static class H4 extends Handler { public H4() { super(Type.Type4); } }
    public static class H5 extends Handler { public H5() { super(Type.Type5); } }
    public static class H6 extends Handler { public H6() { super(Type.Type6); } }
    public static class H7 extends Handler { public H7() { super(Type.Type7); } }
    public static class H8 extends Handler { public H8() { super(Type.Type8); } }
    public static class H9 extends Handler { public H9() { super(Type.Type9); } }
    public static class HA extends Handler { public HA() { super(Type.TypeA); } }

    final static int cCycles = 10000000;

    public static void main(String[] args) {
        H1 h1 = new H1();
        H2 h2 = new H2();
        H3 h3 = new H3();
        H4 h4 = new H4();
        H5 h5 = new H5();
        H6 h6 = new H6();
        H7 h7 = new H7();
        H8 h8 = new H8();
        H9 h9 = new H9();
        HA hA = new HA();

        Date dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerInstanceOf(h1);
            Handler.addHandlerInstanceOf(h2);
            Handler.addHandlerInstanceOf(h3);
            Handler.addHandlerInstanceOf(h4);
            Handler.addHandlerInstanceOf(h5);
            Handler.addHandlerInstanceOf(h6);
            Handler.addHandlerInstanceOf(h7);
            Handler.addHandlerInstanceOf(h8);
            Handler.addHandlerInstanceOf(h9);
            Handler.addHandlerInstanceOf(hA);
        }
        System.out.println("Instance of - " + (new Date().getTime() - dtStart.getTime()));

        dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerSwitch(h1);
            Handler.addHandlerSwitch(h2);
            Handler.addHandlerSwitch(h3);
            Handler.addHandlerSwitch(h4);
            Handler.addHandlerSwitch(h5);
            Handler.addHandlerSwitch(h6);
            Handler.addHandlerSwitch(h7);
            Handler.addHandlerSwitch(h8);
            Handler.addHandlerSwitch(h9);
            Handler.addHandlerSwitch(hA);
        }
        System.out.println("Switch of - " + (new Date().getTime() - dtStart.getTime()));
    }
}

ผลลัพธ์ใดคือ java 6 และอันไหนคือ java 7 คุณกลับมาเยี่ยมชมอีกครั้งภายใต้ Java 8 หรือไม่ มีความหมายมากขึ้นที่นี่คุณกำลังเปรียบเทียบความยาวหากอินสแตนซ์ของสิ่งที่จำเป็นสำหรับการใช้คำสั่ง case บน int ฉันคิดว่าเราคาดหวังว่าสวิตซ์ int จะสว่างขึ้นอย่างรวดเร็ว
Azeroth2b

1
ฉันจำไม่ได้ว่าเกิดอะไรขึ้นเมื่อ 5 ปีที่แล้ว - ฉันคิดว่าทั้ง Java 6 และ Java 7 มีผลลัพธ์ที่คล้ายกันนั่นคือเหตุผลที่มีเพียงผลลัพธ์เดียวเท่านั้นที่ให้ ฉันไม่ได้ลองเปรียบเทียบกับ Java 8 ให้ทดสอบโค้ดทั้งหมด - คุณสามารถคัดลอก / วางและตรวจสอบสภาพแวดล้อมที่คุณต้องการ (หมายเหตุ - ปัจจุบันฉันจะใช้การทดสอบ JMH สำหรับเรื่องนี้)
Xtra Coder

9

instanceof เร็วจริง ๆ ใช้คำสั่ง CPU เพียงไม่กี่คำ

เห็นได้ชัดว่าหากคลาสXนั้นไม่ได้โหลดคลาสย่อย (JVM รู้) instanceofสามารถปรับให้เหมาะสมเป็น:

     x instanceof X    
==>  x.getClass()==X.class  
==>  x.classID == constant_X_ID

ค่าใช้จ่ายหลักเป็นเพียงการอ่าน!

หากXโหลดคลาสย่อยแล้วจำเป็นต้องอ่านอีกสองสามครั้ง พวกเขามีแนวโน้มที่จะอยู่ร่วมกันดังนั้นค่าใช้จ่ายเพิ่มเติมก็ต่ำมากเช่นกัน

ข่าวดีสำหรับทุกคน!


2
สามารถเพิ่มประสิทธิภาพหรือเป็นที่ที่ดีที่สุด? แหล่งที่มา?

@vaxquis สามารถเป็น jvm impl โดยเฉพาะ
RecursiveExceptionException

@itzJanuary ถอนหายใจที่คุณพลาดจุดคำถามของฉันที่นี่: ทุกคนรู้ว่าคอมไพเลอร์ที่สามารถเพิ่มประสิทธิภาพfoo- แต่เป็นfooจริงที่ดีที่สุดในขณะนี้โดยของออราเคิล javac / VM - หรือจะเป็นเพียงไปได้ว่ามันจะทำในอนาคตหรือไม่ นอกจากนี้ฉันถามผู้ตอบว่ามีแหล่งข้อมูลสำรอง (ไม่ว่าจะเป็นเอกสารรหัสต้นฉบับบล็อก dev) ที่ระบุว่าสามารถเพิ่มประสิทธิภาพหรือปรับให้เหมาะสมจริง ๆ ได้ไหม ก็ไม่มีคำตอบนี้เป็นเพียงการสุ่ม musing เกี่ยวกับสิ่งที่คอมไพเลอร์สามารถทำได้

@vaxquis คุณไม่เคยพูดถึง Hotspot VM แต่ในกรณีนี้ฉันไม่ทราบว่าเป็น "ปรับให้เหมาะสม" หรือไม่
RecursiveExceptionException

1
เมื่อเร็ว ๆ นี้อ่านว่า JIT (JVM 8) จะเพิ่มประสิทธิภาพไซต์การโทรสำหรับ 1 หรือ 2 ประเภทโดยการโทรโดยตรง แต่เปลี่ยนกลับเป็น vtable หากพบมากกว่าสองประเภทจริง ดังนั้นการมีเพียงรูปธรรมสองประเภทที่ส่งผ่านไซต์การโทรที่รันไทม์เท่านั้นจึงเป็นข้อได้เปรียบด้านประสิทธิภาพ
simon.watts

5

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


5

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

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

w ขยาย x

อุปกรณ์ที่ใช้

B ขยาย A

C ขยาย B ใช้ y

D ขยาย C, ใช้ z

สมมติว่าฉันกำลังประมวลผลอินสแตนซ์ของ D ซึ่งเป็นวัตถุ d การคำนวณ (d อินสแตนซ์ x) จำเป็นต้องใช้ d.getClass () วนลูปผ่านอินเทอร์เฟซที่ใช้เพื่อทราบว่าหนึ่งคือ == ถึง x และถ้าไม่ทำเช่นนั้นซ้ำสำหรับบรรพบุรุษทั้งหมดของพวกเขา ... ในกรณีของเรา หากคุณทำการสำรวจอย่างกว้างแรกของต้นไม้ต้นนั้นให้เปรียบเทียบอย่างน้อย 8 รายการโดยสมมุติว่า y และ z ไม่ขยายอะไรเลย ...

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

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

นี่คือ 2 เซ็นต์ของฉันฉันหวังว่าพวกเขาช่วย ...


5

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

หากคุณสามารถใช้ xClass == String.class นี่จะเร็วกว่า หมายเหตุ: คุณไม่จำเป็นต้องใช้ instanceof สำหรับคลาสสุดท้าย


1
Btw คุณหมายถึงอะไรโดย "ไม่ต้องการอินสแตนซ์ของคลาสสุดท้าย"
Pacerier

คลาสสุดท้ายไม่สามารถมีคลาสย่อยได้ ในกรณีx.getClass() == Class.classนี้เหมือนกับx instanceof Class
Peter Lawrey

เจ๋งสมมติว่า x ไม่ใช่โมฆะคุณต้องการอะไร?
Pacerier

จุดดี. มันขึ้นอยู่กับว่าฉันคาดว่าxจะเป็นnullหรือไม่ (หรือสิ่งใดที่ชัดเจนกว่า)
Peter Lawrey

ฉันเพิ่งรู้ว่าเราสามารถใช้ java.lang.class.isAssignableFrom ได้เช่นกันคุณทราบหรือไม่ว่าคำหลักอินสแตนซ์ของฟังก์ชั่นภายในใช้ฟังก์ชันเช่นนี้
Pacerier

4

โดยทั่วไปสาเหตุที่ตัวดำเนินการ "instanceof" ถูกขมวดคิ้วในกรณีเช่นนั้น (โดยที่ instanceof กำลังตรวจสอบคลาสย่อยของคลาสพื้นฐานนี้) เป็นเพราะสิ่งที่คุณควรทำคือย้ายการดำเนินการไปยังวิธีการและแทนที่มันตามความเหมาะสม subclasses ตัวอย่างเช่นหากคุณมี:

if (o instanceof Class1)
   doThis();
else if (o instanceof Class2)
   doThat();
//...

คุณสามารถแทนที่ด้วย

o.doEverything();

แล้วมีการใช้งานของ "doEverything ()" ในการโทร Class1 "doThis ()" และในการโทร Class2 "doThat ()" และอื่น ๆ


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

4

'อินสแตนซ์ของ' เป็นตัวดำเนินการจริง ๆ เช่น + หรือ - และฉันเชื่อว่ามีคำสั่ง JVM bytecode ของตัวเอง มันควรจะเร็วมาก

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


4

Demian และ Paul พูดถึงจุดดี อย่างไรก็ตามการวางตำแหน่งของรหัสเพื่อดำเนินการจริง ๆ ขึ้นอยู่กับวิธีที่คุณต้องการใช้ข้อมูล ...

ฉันเป็นแฟนตัวยงของวัตถุข้อมูลขนาดเล็กที่สามารถใช้ได้หลายวิธี ถ้าคุณทำตามวิธีการแทนที่ (polymorphic) วัตถุของคุณสามารถใช้ "ทางเดียว" เท่านั้น

นี่คือที่มาของรูปแบบ ...

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

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

หวังว่านี่จะเป็นแรงบันดาลใจให้กับแนวคิดอื่น ๆ ...

package com.javadude.sample;

import java.util.HashMap;
import java.util.Map;

public class StrategyExample {
    static class SomeCommonSuperType {}
    static class SubType1 extends SomeCommonSuperType {}
    static class SubType2 extends SomeCommonSuperType {}
    static class SubType3 extends SomeCommonSuperType {}

    static interface Handler<T extends SomeCommonSuperType> {
        Object handle(T object);
    }

    static class HandlerMap {
        private Map<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>> handlers_ =
            new HashMap<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>>();
        public <T extends SomeCommonSuperType> void add(Class<T> c, Handler<T> handler) {
            handlers_.put(c, handler);
        }
        @SuppressWarnings("unchecked")
        public <T extends SomeCommonSuperType> Object handle(T o) {
            return ((Handler<T>) handlers_.get(o.getClass())).handle(o);
        }
    }

    public static void main(String[] args) {
        HandlerMap handlerMap = new HandlerMap();

        handlerMap.add(SubType1.class, new Handler<SubType1>() {
            @Override public Object handle(SubType1 object) {
                System.out.println("Handling SubType1");
                return null;
            } });
        handlerMap.add(SubType2.class, new Handler<SubType2>() {
            @Override public Object handle(SubType2 object) {
                System.out.println("Handling SubType2");
                return null;
            } });
        handlerMap.add(SubType3.class, new Handler<SubType3>() {
            @Override public Object handle(SubType3 object) {
                System.out.println("Handling SubType3");
                return null;
            } });

        SubType1 subType1 = new SubType1();
        handlerMap.handle(subType1);
        SubType2 subType2 = new SubType2();
        handlerMap.handle(subType2);
        SubType3 subType3 = new SubType3();
        handlerMap.handle(subType3);
    }
}

4

ฉันเขียนการทดสอบประสิทธิภาพตาม jmh-java-benchmark-archetype: 2.21 JDK เป็น openjdk และรุ่นคือ 1.8.0_212 เครื่องทดสอบคือ mac pro ผลการทดสอบคือ:

Benchmark                Mode  Cnt    Score   Error   Units
MyBenchmark.getClasses  thrpt   30  510.818 ± 4.190  ops/us
MyBenchmark.instanceOf  thrpt   30  503.826 ± 5.546  ops/us

ผลลัพธ์แสดงว่า: getClass ดีกว่า instanceOf ซึ่งตรงกันข้ามกับการทดสอบอื่น ๆ อย่างไรก็ตามฉันไม่รู้ว่าทำไม

รหัสทดสอบด้านล่าง:

public class MyBenchmark {

public static final Object a = new LinkedHashMap<String, String>();

@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean instanceOf() {
    return a instanceof Map;
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean getClasses() {
    return a.getClass() == HashMap.class;
}

public static void main(String[] args) throws RunnerException {
    Options opt =
        new OptionsBuilder().include(MyBenchmark.class.getSimpleName()).warmupIterations(20).measurementIterations(30).forks(1).build();
    new Runner(opt).run();
}
}

ถ้าฉันจะเก็งกำไรสิ่งที่อินสแตนซ์ของทำจะซับซ้อนกว่านี้ การตรวจสอบ getClass () == จะทำการตรวจสอบ 1: 1 อย่างแม่นยำโดยที่ instanceof ตรวจสอบลำดับชั้นเช่น myHashSet instanceof Collection จะผ่าน แต่ myHashSet.getClass () == Collection.class จะไม่ โดยพื้นฐานแล้วพวกเขาไม่ได้ทำงานเทียบเท่าดังนั้นฉันไม่แปลกใจเกินไปที่ประสิทธิภาพจะแตกต่างกันเช่นกัน
AMTerp

3

มันยากที่จะพูดว่า JVM บางตัวใช้อินสแตนซ์ของ แต่ในกรณีส่วนใหญ่ Objects นั้นเปรียบได้กับ structs และคลาสเป็นอย่างดีและ struct object ทุกตัวมีตัวชี้ไปที่ struct ของคลาสมันเป็นตัวอย่างของ ดังนั้นอินสแตนซ์สำหรับ

if (o instanceof java.lang.String)

อาจเร็วเท่ากับรหัส C ต่อไปนี้

if (objectStruct->iAmInstanceOf == &java_lang_String_class)

สมมติว่าคอมไพเลอร์ JIT อยู่ในสถานที่และทำงานได้ดี

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

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


1
มันไม่ต้องคิดออกว่า o สืบทอดมาจาก java.lang.String หรือไม่?
WW

1
นั่นเป็นเหตุผลที่ฉันพูดว่า "อาจ" เร็ว ในความเป็นจริงมันทำการวนรอบก่อนอื่นให้ตรวจสอบ iAmInstanceOf กับคลาสที่มีปัญหาจากนั้นขึ้นไปที่แผนผังการสืบทอดของ o และทำซ้ำการตรวจสอบนี้สำหรับทุก ๆ คลาสซูเปอร์ของ o (ดังนั้นจึงอาจต้องรันลูปนี้สองสามครั้ง สำหรับการแข่งขัน)
Mecki

3

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


2

InstanceOfเป็นคำเตือนของการออกแบบ Object Oriented ที่ไม่ดี

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

เพื่อให้ตัวอย่างการเขียนโปรแกรมแบบง่าย ๆ มีขนาดเล็กมาก

if (SomeObject instanceOf Integer) {
  [do something]
}
if (SomeObject instanceOf Double) {
  [do something different]
}

สถาปัตยกรรมที่น่าสงสารตัวเลือกที่ดีกว่าน่าจะมี SomeObject เป็นคลาสพาเรนต์ของคลาสย่อยสองคลาสที่แต่ละคลาสย่อยจะแทนที่เมธอด (doSomething) ดังนั้นโค้ดจะมีลักษณะดังนี้:

Someobject.doSomething();

61
ฉันรู้เรื่องนั้น นั่นไม่ใช่สิ่งที่ฉันถาม
Josh

ไม่แน่ใจว่าจะลงคะแนนเสียงขึ้นนี้หรือไม่มันเป็นจุดที่ดี แต่ไม่ตอบคำถามที่ถาม ...
jklp

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

6
นอกจากนี้ถ้าคลาสลูกของ SomeObject เป็นวัตถุที่มีค่าแล้วคุณไม่ต้องการใส่ตรรกะในพวกเขา เช่น Pie และ Roast อาจไม่ใช่ตำแหน่งที่ถูกต้องสำหรับตรรกะ putInOven () และ putInMouth ()
sk.

การทำอาหารด้วยตนเองพายและย่างจะน่ากลัว แต่
binboavetonik

2

ในเวอร์ชั่น Java สมัยใหม่ตัวดำเนินการ instanceof นั้นเร็วกว่าเป็นการเรียกเมธอดธรรมดา หมายความว่า:

if(a instanceof AnyObject){
}

เร็วกว่า:

if(a.getType() == XYZ){
}

อีกสิ่งหนึ่งคือถ้าคุณต้องการเรียงซ้อนอินสแตนซ์จำนวนมาก จากนั้นสวิตช์ที่เรียกใช้เพียงครั้งเดียว getType () จะเร็วขึ้น


1

หากความเร็วคือเป้าหมายเดียวของคุณให้ใช้ค่าคงที่ int เพื่อระบุคลาสย่อยที่ดูเหมือนว่าจะโกนเป็นมิลลิวินาที

static final int ID_A = 0;
static final int ID_B = 1;
abstract class Base {
  final int id;
  Base(int i) { id = i; }
}
class A extends Base {
 A() { super(ID_A); }
}
class B extends Base {
 B() { super(ID_B); }
}
...
Base obj = ...
switch(obj.id) {
case  ID_A: .... break;
case  ID_B: .... break;
}

การออกแบบ OO ที่แย่มาก แต่ถ้าการวิเคราะห์ประสิทธิภาพของคุณบ่งบอกว่านี่คือจุดที่คุณเป็นคอขวด ในรหัสของฉันรหัสการจัดส่งใช้เวลา 10% ของเวลาในการดำเนินการทั้งหมดและอาจส่งผลให้มีการปรับปรุงความเร็วโดยรวม 1%


0

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

คุณควรบอกเพิ่มเติมเกี่ยวกับปัญหาบางทีคุณอาจใช้ร้านค้าแบบเชื่อมโยงเช่น Map <Class, Object> หากคุณสนใจเฉพาะรูปธรรมเท่านั้น


0

สำหรับบันทึกของปีเตอร์ลอว์เรย์ว่าคุณไม่ต้องการอินสแตนซ์สำหรับชั้นเรียนสุดท้ายและสามารถใช้ความเท่าเทียมในการอ้างอิงได้โปรดระวัง! แม้ว่าคลาสสุดท้ายจะไม่สามารถขยายได้ แต่จะไม่รับประกันว่าจะโหลดโดย classloader เดียวกัน ใช้ x.getClass () == SomeFinal.class หรือ ilk ของมันเท่านั้นหากคุณแน่ใจว่ามี classloader เดียวเท่านั้นที่เล่นในส่วนของรหัสนั้น


4
หากคลาสถูกโหลดโดย classloader อื่นฉันไม่คิดว่าอินสแตนซ์ของมันจะจับคู่กัน
Peter Lawrey

0

ฉันชอบวิธี Enum ด้วยเช่นกัน แต่ฉันจะใช้คลาสฐานนามธรรมเพื่อบังคับให้คลาสย่อยใช้getType()วิธีนี้

public abstract class Base
{
  protected enum TYPE
  {
    DERIVED_A, DERIVED_B
  }

  public abstract TYPE getType();

  class DerivedA extends Base
  {
    @Override
    public TYPE getType()
    {
      return TYPE.DERIVED_A;
    }
  }

  class DerivedB extends Base
  {
    @Override
    public TYPE getType()
    {
      return TYPE.DERIVED_B;
    }
  }
}

0

ฉันคิดว่ามันอาจจะคุ้มค่าที่จะส่งตัวอย่างตอบโต้ไปยังฉันทามติทั่วไปในหน้านี้ว่า "อินสแตนซ์ของ" นั้นไม่แพงพอที่จะกังวล ฉันพบว่าฉันมีโค้ดบางส่วนในลูปภายในที่ (ในความพยายามครั้งประวัติศาสตร์ในการเพิ่มประสิทธิภาพ)

if (!(seq instanceof SingleItem)) {
  seq = seq.head();
}

โดยที่ call head () บน SingleItem จะส่งคืนค่าที่ไม่เปลี่ยนแปลง แทนที่รหัสด้วย

seq = seq.head();

ทำให้ฉันเพิ่มความเร็วจาก 269ms เป็น 169ms แม้ว่าจะมีบางสิ่งที่ค่อนข้างหนักที่เกิดขึ้นในลูปเช่นการแปลงสตริงเป็นสองครั้ง แน่นอนว่าการเร่งความเร็วนั้นมีสาเหตุมาจากการกำจัดสาขาที่มีเงื่อนไขมากกว่าที่จะกำจัดอินสแตนซ์ของผู้ปฏิบัติงานเอง แต่ฉันคิดว่ามันควรค่าแก่การกล่าวขวัญ


อาจเป็นเพราะifตัวของมันเอง หากการกระจายตัวของtrues และfalses ใกล้เคียงกับการดำเนินการเก็งกำไรกลายเป็นไร้ประโยชน์ซึ่งนำไปสู่การล่าช้าที่สำคัญ
Dmytro

-4

คุณกำลังมุ่งเน้นไปที่สิ่งที่ผิด ความแตกต่างระหว่าง instanceof และวิธีอื่นใดสำหรับการตรวจสอบสิ่งเดียวกันอาจไม่สามารถวัดได้ หากประสิทธิภาพมีความสำคัญ Java อาจเป็นภาษาที่ผิด สาเหตุหลักที่คุณไม่สามารถควบคุมได้เมื่อ VM ตัดสินใจว่าต้องการรวบรวมขยะซึ่งสามารถใช้ CPU เป็น 100% เป็นเวลาหลายวินาทีในโปรแกรมขนาดใหญ่ (MagicDraw 10 ยอดเยี่ยมสำหรับเรื่องนี้) หากคุณไม่สามารถควบคุมคอมพิวเตอร์ทุกเครื่องโปรแกรมนี้จะทำงานบนคุณไม่สามารถรับประกันได้ว่าจะใช้ JVM เวอร์ชันใดและรุ่นเก่าหลายรุ่นมีปัญหาเรื่องความเร็วที่สำคัญ หากเป็นแอพเล็ก ๆ คุณอาจใช้งาน Java ได้ แต่ถ้าคุณอ่านและทิ้งข้อมูลอยู่ตลอดเวลาคุณจะสังเกตเห็นเมื่อ GC เข้ามา


7
นั่นเป็นความจริงน้อยกว่าของอัลกอริทึมการรวบรวมขยะ Java ที่ทันสมัยกว่าที่เคยเป็นมา แม้แต่อัลกอริธึมที่ง่ายที่สุดก็ไม่สนใจจำนวนหน่วยความจำที่คุณทิ้งไปหลังจากคุณใช้งาน - พวกเขาแค่ดูแลว่าเก็บไว้ในคอลเล็กชั่นรุ่นใหม่เพียงใด
บิลมิเชล

3
เยี่ยมมากยกเว้นฉันใช้ JVM ล่าสุดและคอมพิวเตอร์ของฉันยังคงรวบรวมข้อมูลเมื่อ GC ทำงาน บนเซิร์ฟเวอร์ RAM 3GB แบบดูอัลคอร์ Java ไม่ใช่ภาษาที่ใช้ถ้าประสิทธิภาพมีความสำคัญ
tloach

@ David: คุณไม่จำเป็นต้องใช้เรียลไทม์เพื่อมีปัญหาเมื่อแอพของคุณหายไปเป็นระยะเวลาหนึ่ง สิ่งที่สนุกที่ฉันพบคือแอป java ที่เชื่อมต่อกับ TCP สตรีมที่เสียชีวิตเมื่อ GC รันเพราะมันไม่ได้ปิดสตรีมก่อนและไม่สามารถรับมือกับการรับส่งข้อมูลเครือข่ายมากเกินไปเมื่อมันกลับมา - มันจะทันที เข้าสู่ลูปที่ GC ทำงานเมื่อแอปทำงานต่อจะพยายามปั่นผ่านข้อมูลจำนวนมากซึ่งทำให้หน่วยความจำหมดซึ่งเรียกใช้ GC และอื่น ๆ Java เหมาะสำหรับงานจำนวนมาก แต่ไม่ใช่งานที่มีมาก ประสิทธิภาพที่แข็งแกร่งคือความต้องการ
tloach

6
@tachach ฟังดูแล้วเหมือนการออกแบบแอพที่ไม่ดี คุณพูดถึง "การแสดง" ราวกับว่ามันเป็นหนึ่งมิติ ฉันได้ทำงานกับ (และ) แอพพลิเคชั่นจาวาจำนวนมากซึ่งเป็นตัวอย่างในการให้การวิเคราะห์เชิงสถิติเชิงโต้ตอบที่รวดเร็วและการสร้างภาพของชุดข้อมูลขนาดใหญ่มากหรือนักแสดงในการประมวลผลปริมาณธุรกรรมขนาดใหญ่มากอย่างรวดเร็ว "ประสิทธิภาพ" ไม่ได้เป็นเพียงเรื่องเดียวและความจริงที่ว่าใครบางคนสามารถเขียนแอปพลิเคชันที่จัดการหน่วยความจำไม่ดีและทำให้ GC เข้ามาในทางของตัวเองไม่ได้แปลว่าอะไรก็ตามที่ต้องการ "ประสิทธิภาพ"
David Moles
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.