ইন্টে রিমাইন্ডার অপারেটর জাভা.ইউটি.অবজেক্টস.আরকিয়ারনন নল?


12

আমি কয়েকটি অভ্যন্তরীণ পদ্ধতি থেকে যথাসম্ভব পারফরম্যান্স পাওয়ার চেষ্টা করছি।

জাভা কোডটি হ'ল:

List<DirectoryTaxonomyWriter> writers = Lists.newArrayList();
private final int taxos = 4;

[...]

@Override
public int getParent(final int globalOrdinal) throws IOException {
    final int bin = globalOrdinal % this.taxos;
    final int ordinalInBin = globalOrdinal / this.taxos;
    return this.writers.get(bin).getParent(ordinalInBin) * this.taxos + bin; //global parent
}

আমার প্রোফাইলে আমি দেখেছি 1% সিপিইউ ব্যয় হয়েছে java.util.Objects.requireNonNull, তবে আমি এটি কল করি না। বাইকোড পরিদর্শন করার সময়, আমি এটি দেখেছি:

 public getParent(I)I throws java/io/IOException 
   L0
    LINENUMBER 70 L0
    ILOAD 1
    ALOAD 0
    INVOKESTATIC java/util/Objects.requireNonNull (Ljava/lang/Object;)Ljava/lang/Object;
    POP
    BIPUSH 8
    IREM
    ISTORE 2

সুতরাং সংকলক এটি (অকেজো?) চেক উত্পন্ন করে। আমি আদিমগুলিতে কাজ করি, যা nullযাইহোক হতে পারে না , তাই সংকলক কেন এই লাইনটি উত্পন্ন করে? এটা কি বাগ? নাকি 'নরমাল' আচরণ?

(আমি বিটমাস্ক নিয়ে কাজ করতে পারি, তবে আমি কেবল কৌতূহলী)

[হালনাগাদ]

  1. অপারেটরটির সাথে এর কিছু করার নেই বলে মনে হচ্ছে (নীচে উত্তর দেখুন)

  2. গ্রহণের সংকলক (সংস্করণ 4.10) ব্যবহার করে আমি এটি আরও যুক্তিসঙ্গত ফলাফল পেয়েছি:

    পাবলিক গেটপ্যারেন্ট (আই) আমি জাভা / আইও / আইওএক্সেপশন নিক্ষেপ করি 
       L0
        লিনেন্ডার 77 এল0
        ILOAD 1
        ICONST_4
        IREM
        ইস্টোর 2
       এটি L1
        লিনেনদার 78 এল

সুতরাং এটি আরও যৌক্তিক।


@ লিনো নিশ্চিত, তবে এটি কারণগুলির সাথে 70 লাইনের জন্য প্রাসঙ্গিক নয়INVOKESTATIC
রোবউ

আপনি কোন সংকলক ব্যবহার করেন? সাধারণ javacএটি উত্পন্ন করে না।
আপানগিন

আপনি কোন সংকলক ব্যবহার করেন? জাভা সংস্করণ, ওপেনজেডক / ওরাকল / ইত্যাদি। সম্পাদনা করুন: ওফস, @ পাঙ্গিন দ্রুত ছিল, দুঃখিত
লুগিয়েরি

1
এটি openjdk version "11.0.6" 2020-01-14উবুন্টু 64 বিটে জাভা 11 এর সাথে ইন্টেলিজ 2019.3 থেকে সংকলিত হয়েছে ।
রবউউ

উত্তর:


3

কেন না?

অভিমানী

class C {
    private final int taxos = 4;

    public int test() {
        final int a = 7;
        final int b = this.taxos;
        return a % b;
    }
}

মত একটি কল c.test()যেখানে cহিসাবে ঘোষিত হয় C আবশ্যক নিক্ষেপ যখন cহয় null। আপনার পদ্ধতি সমান

    public int test() {
        return 3; // `7 % 4`
    }

যেমন আপনি কেবল ধ্রুবকের সাথে কাজ করেন। testঅ-স্থির হওয়ার সাথে সাথে চেকটিও করতে হবে। সাধারণত, যখন কোনও ক্ষেত্র অ্যাক্সেস হয়ে যায় বা কোনও স্থিতিশীল পদ্ধতি কল করা হয় তবে এটি স্পষ্টভাবে সম্পন্ন হবে তবে আপনি এটি করবেন না। সুতরাং একটি স্পষ্ট চেক প্রয়োজন। একটি সম্ভাবনা কল করা হয় Objects.requireNonNull

বাইটকোড

ভুলে যাবেন না যে বাইটকোড মূলত পারফরম্যান্সের জন্য অপ্রাসঙ্গিক। এর কাজটি javacহ'ল এমন কিছু বাইটকোড উত্পাদন করা যার সম্পাদনাটি আপনার উত্স কোডের সাথে মিলে। এটি কোনও অপ্টিমাইজেশন করার জন্য নয় , কারণ অনুকূলিত কোডটি সাধারণত দীর্ঘতর এবং বিশ্লেষণ করা আরও শক্ত হয়, অন্যদিকে বাইটকোডটি আসলে জেআইটি সংকলককে অনুকূলকরণের জন্য উত্স কোড । সুতরাং javacএটি সহজ রাখা আশা করা হয় ....

পরিবেশনাটি

আমার প্রোফাইলে আমি দেখেছি 1% সিপিইউ ব্যয় করছে java.util.Objects.requireNonNull

আমি প্রথমে প্রোফাইলারকে দোষ দেব। প্রোফাইলিং জাভা বেশ শক্ত এবং আপনি কখনই নিখুঁত ফলাফল আশা করতে পারেন না।

আপনার সম্ভবত পদ্ধতিটি স্থির করার চেষ্টা করা উচিত। নাল চেক সম্পর্কে আপনার অবশ্যই এই নিবন্ধটি পড়া উচিত ।


1
আপনার অন্তর্দৃষ্টিপূর্ণ উত্তরের জন্য @ maaartinus ধন্যবাদ। আমি অবশ্যই আপনার লিঙ্কিত নিবন্ধটি পড়ব।
রবউউ

1
"পরীক্ষাটি অ স্থির হওয়ার সাথে সাথে অবশ্যই চেক করতে হবে" আসলে, thisঅ-নয় কিনা তা পরীক্ষা করার কোনও কারণ নেই null। আপনি যেমন বলেছিলেন, ঠিক তেমন একটি কল c.test()অবশ্যই ব্যর্থ হবে এবং এটি পদ্ধতিতে প্রবেশের পরিবর্তে তাত্ক্ষণিকভাবে ব্যর্থ হতে হবে। এর মধ্যে , কখনই হতে পারে না (অন্যথায় কোনও জেভিএম বাগ থাকতে পারে)। সুতরাং চেক করার দরকার নেই। প্রকৃত ফিক্স ক্ষেত্র পরিবর্তন হওয়া উচিত করতে সেখানে একটি কম্পাইল-টাইম ধ্রুবক জন্য প্রতিটি উদাহরণের মেমরি সংরক্ষণ করার কোনো মানে নেই। তারপর, কিনা হয় অপ্রাসঙ্গিক। cnulltest()thisnulltaxosstatictest()static
হলগার

2

ঠিক আছে বলে মনে হচ্ছে আমার প্রশ্নটি 'ভুল' ছিল কারণ এর অপারেটরের সাথে কিছুই করার নেই, বরং ক্ষেত্রটিই। এখনও কেন জানি না ..

   public int test() {
        final int a = 7;
        final int b = this.taxos;
        return a % b;
    }

যা রূপান্তরিত:

  public test()I
   L0
    LINENUMBER 51 L0
    BIPUSH 7
    ISTORE 1
   L1
    LINENUMBER 52 L1
    ALOAD 0
    INVOKESTATIC java/util/Objects.requireNonNull (Ljava/lang/Object;)Ljava/lang/Object;
    POP
    ICONST_4
    ISTORE 2
   L2
    LINENUMBER 53 L2
    BIPUSH 7
    ILOAD 2
    IREM
    IRETURN

1
সংকলক আসলে ভয় পেতে পারে যে thisরেফারেন্স null? এটা কি সম্ভব হবে?
আটলান্টাস

1
না যা কোনও অর্থবোধ করে না, যদি না সংকলক ক্ষেত্রটিকে Integerকোনওরকম সংকলন করে , এবং এটি অটোবক্সিংয়ের ফলাফল?
রবউউ

1
ALOAD 0রেফারেন্স না this? সুতরাং এটি বোঝা যাবে (সত্য নয়) যে সংকলকটি একটি নালচেক যোগ করেছে
লিনো

1
সুতরাং সংকলক আসলে একটি নাল চেক যোগ করা হয় this? দুর্দান্ত: /
রবউউ

1
আমি javacআগামীকাল যাচাই করতে কমান্ড-লাইন দিয়ে একটি সংক্ষিপ্ত কোড তৈরি করার চেষ্টা করব ; এবং যদি এটিও এই আচরণটি প্রদর্শন করে তবে আমি মনে করি এটি জাভ্যাক-বাগ হতে পারে?
রবউউ

2

প্রথমত, এই আচরণের একটি সর্বনিম্ন পুনরুত্পাদনযোগ্য উদাহরণ:

/**
 * OS:              Windows 10 64x
 * javac version:   13.0.1
 */
public class Test {
    private final int bar = 5;

    /**
     * public int foo();
     *   Code:
     *     0: iconst_5
     *     1: ireturn
     */
    public int foo() {
        return bar;
    }

    /**
     * public int foo2();
     *   Code:
     *     0: aload_0
     *     1: invokestatic  #13     // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
     *     4: pop
     *     5: iconst_5
     *     6: ireturn
     */
    public int foo2() {
        return this.bar;
    }
}

আচরণ কারণ কিভাবে জাভা কম্পাইলার সেরা অনুকূল রূপ হল কম্পাইল-টাইম ধ্রুবক

নোট করুন যে foo()কোনও বাইট রেফারেন্সের বাইট কোডে এর মান পেতে অ্যাক্সেস করা হয় না bar। কারণ এটি একটি সংকলন-সময় ধ্রুবক এবং এইভাবে JVM iconst_5এই মানটি ফেরত দেওয়ার জন্য অপারেশনটি কেবল কার্যকর করতে পারে ।

barএকটি কম-কম্পাইল সময় ধ্রুবক পরিবর্তনের সময় (হয় finalকীওয়ার্ডটি সরিয়ে দিয়ে বা ঘোষণার মধ্যে আরম্ভ না করে তবে নির্মাণকারীর ভিতরে) আপনি পাবেন:

/**
 * OS:              Windows 10 64x
 * javac version:   13.0.1
 */
public class Test2 {
    private int bar = 5;

    /**
     * public int foo();
     *   Code:
     *     0: aload_0
     *     1: getfield      #7
     *     4: ireturn
     */
    public int foo() {
        return bar;
    }

    /**
     * public int foo2();
     *   Code:
     *     0: aload_0
     *     1: getfield      #7
     *     4: ireturn
     */
    public int foo2() {
        return this.bar;
    }
}

যেখানে aload_0পাহাড় জমে রেফারেন্স এর thisসম্মুখের প্রতীক স্ট্যাক তারপর পেতে barক্ষেত্র এই বস্তুর।

এখানে সংকলকটি যথেষ্ট চৌকস তা লক্ষ করার জন্য aload_0( thisসদস্য ফাংশনের ক্ষেত্রে রেফারেন্স) যৌক্তিকভাবে হতে পারে না null

এখন আপনার ক্ষেত্রে আসলে একটি অনুপস্থিত সংকলক অপ্টিমাইজেশন?

@ Maaartinus উত্তর দেখুন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.