java - আউটপুট-1 লুপে স্ল্যাশ হয়ে যায়




string while-loop (2)

এটি openjdk version "1.8.0_222" (আমার বিশ্লেষণে ব্যবহৃত), ওপেনজেডকে 12.0.1 (ওলেকসান্ডার পাইরোহভ অনুসারে) এবং ওপেনজেডিকে 13 (কার্লোস হুবার্গারের মতে) এর সাথে নির্ভরযোগ্যভাবে পুনরুত্পাদন করা যেতে পারে (বা আপনি যা চান তার উপর নির্ভর করে পুনরুত্পাদন করা যায় না) ।

আমি -XX:+PrintCompilation সাথে -XX:+PrintCompilation উভয় আচরণ পেতে যথেষ্ট সময় -XX:+PrintCompilation এবং এখানে পার্থক্য রয়েছে।

বগি বাস্তবায়ন (আউটপুট প্রদর্শন করে):

 --- Previous lines are identical in both
 54   17       3       java.lang.AbstractStringBuilder::<init> (12 bytes)
 54   23       3       LoopOutPut::test (57 bytes)
 54   18       3       java.lang.String::<init> (82 bytes)
 55   21       3       java.lang.AbstractStringBuilder::append (62 bytes)
 55   26       4       java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes)
 55   20       3       java.lang.StringBuilder::<init> (7 bytes)
 56   19       3       java.lang.StringBuilder::toString (17 bytes)
 56   25       3       java.lang.Integer::getChars (131 bytes)
 56   22       3       java.lang.StringBuilder::append (8 bytes)
 56   27       4       java.lang.String::equals (81 bytes)
 56   10       3       java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes)   made not entrant
 56   28       4       java.lang.AbstractStringBuilder::append (50 bytes)
 56   29       4       java.lang.String::getChars (62 bytes)
 56   24       3       java.lang.Integer::stringSize (21 bytes)
 58   14       3       java.lang.String::getChars (62 bytes)   made not entrant
 58   33       4       LoopOutPut::test (57 bytes)
 59   13       3       java.lang.AbstractStringBuilder::append (50 bytes)   made not entrant
 59   34       4       java.lang.Integer::getChars (131 bytes)
 60    3       3       java.lang.String::equals (81 bytes)   made not entrant
 60   30       4       java.util.Arrays::copyOfRange (63 bytes)
 61   25       3       java.lang.Integer::getChars (131 bytes)   made not entrant
 61   32       4       java.lang.String::<init> (82 bytes)
 61   16       3       java.util.Arrays::copyOfRange (63 bytes)   made not entrant
 61   31       4       java.lang.AbstractStringBuilder::append (62 bytes)
 61   23       3       LoopOutPut::test (57 bytes)   made not entrant
 61   33       4       LoopOutPut::test (57 bytes)   made not entrant
 62   35       3       LoopOutPut::test (57 bytes)
 63   36       4       java.lang.StringBuilder::append (8 bytes)
 63   18       3       java.lang.String::<init> (82 bytes)   made not entrant
 63   38       4       java.lang.StringBuilder::append (8 bytes)
 64   21       3       java.lang.AbstractStringBuilder::append (62 bytes)   made not entrant

সঠিক রান (কোনও প্রদর্শন নেই):

 --- Previous lines identical in both
 55   23       3       LoopOutPut::test (57 bytes)
 55   17       3       java.lang.AbstractStringBuilder::<init> (12 bytes)
 56   18       3       java.lang.String::<init> (82 bytes)
 56   20       3       java.lang.StringBuilder::<init> (7 bytes)
 56   21       3       java.lang.AbstractStringBuilder::append (62 bytes)
 56   26       4       java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes)
 56   19       3       java.lang.StringBuilder::toString (17 bytes)
 57   22       3       java.lang.StringBuilder::append (8 bytes)
 57   24       3       java.lang.Integer::stringSize (21 bytes)
 57   25       3       java.lang.Integer::getChars (131 bytes)
 57   27       4       java.lang.String::equals (81 bytes)
 57   28       4       java.lang.AbstractStringBuilder::append (50 bytes)
 57   10       3       java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes)   made not entrant
 57   29       4       java.util.Arrays::copyOfRange (63 bytes)
 60   16       3       java.util.Arrays::copyOfRange (63 bytes)   made not entrant
 60   13       3       java.lang.AbstractStringBuilder::append (50 bytes)   made not entrant
 60   33       4       LoopOutPut::test (57 bytes)
 60   34       4       java.lang.Integer::getChars (131 bytes)
 61    3       3       java.lang.String::equals (81 bytes)   made not entrant
 61   32       4       java.lang.String::<init> (82 bytes)
 62   25       3       java.lang.Integer::getChars (131 bytes)   made not entrant
 62   30       4       java.lang.AbstractStringBuilder::append (62 bytes)
 63   18       3       java.lang.String::<init> (82 bytes)   made not entrant
 63   31       4       java.lang.String::getChars (62 bytes)

আমরা একটি উল্লেখযোগ্য পার্থক্য লক্ষ্য করতে পারি। সঠিক নির্বাহের সাহায্যে আমরা test() দু'বার সংকলন করি। একবার শুরুর দিকে এবং তারপরে আবার (সম্ভবতঃ কারণটি পদ্ধতিটি কতটা গরম তা জেআইটি লক্ষ্য করে)। বগি এক্সিকিউশন test() ) 5 বার সংকলন করা হয় (বা ডিকম্পাইল)।

অতিরিক্ত হিসাবে, -XX:-TieredCompilation সাথে চলমান -XX:-TieredCompilation (যা হয় ব্যাখ্যা করে, বা C2 ব্যবহার করে) বা- -Xbatch (যা সংকলনকে মূল থ্রেডে সমান্তরালভাবে পরিবর্তে চালিত করতে বাধ্য করে), আউটপুটটি গ্যারান্টিযুক্ত এবং 30000 পুনরাবৃত্তির সাথে একটি প্রিন্ট আউট করে প্রচুর স্টাফ, সুতরাং C2 সংকলকটিকে অপরাধী বলে মনে হচ্ছে। এটি -XX:TieredStopAtLevel=1 সাথে চলার মাধ্যমে নিশ্চিত করা হয়েছে -XX:TieredStopAtLevel=1 , যা C2 অক্ষম করে এবং আউটপুট উত্পাদন করে না (4 স্তরের স্তরে থামিয়ে আবার বাগটি দেখায়)।

সঠিক সম্পাদনায়, পদ্ধতিটি প্রথমে 3 স্তর সংকলন, পরে স্তরের 4 দিয়ে সংকলিত হয়।

বগি এক্সিকিউশনে পূর্ববর্তী সংকলনগুলি চিহ্নিত করা হয় ( made non entrant ) এবং এটি আবার স্তর 3 (যা C1 , পূর্ববর্তী লিঙ্কটি দেখুন) তে সংকলিত হয়েছে।

সুতরাং এটি অবশ্যই C2 একটি বাগ, যদিও আমি শ্রেনী 3 সংকলনে ফিরে যাচ্ছি তা এটিকে প্রভাবিত করে কিনা (এবং কেন এটি এখনও 3 স্তরে ফিরে যাচ্ছে, এখনও অনেকগুলি অনিশ্চয়তা রয়েছে) তা আমি নিশ্চিত নই।

খরগোশের গর্তের আরও গভীরে যাওয়ার জন্য আপনি নিম্নলিখিত লাইনের সাথে অ্যাসেমব্লি কোড তৈরি করতে পারেন (এসেম্বলি প্রিন্টিং সক্ষম করতে এটিও দেখুন)।

java -XX:+PrintCompilation -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly LoopOutPut > broken.asm

এই মুহুর্তে আমি দক্ষতার বাইরে চলে যেতে শুরু করছি, পূর্ববর্তী সংকলিত সংস্করণগুলি বাতিল হয়ে গেলে বগী আচরণটি প্রদর্শিত হতে শুরু করে, তবে 90 এর apangin থেকে আমার যে সামান্য সমাবেশ দক্ষতা রয়েছে, তাই আমি apangin ধরে রাখার চেষ্টা করব যেহেতু তিনি সম্ভবত এমন একজনের মধ্যে আছেন যারা জানেন কী knows

সম্ভবত এই সম্পর্কে ইতিমধ্যে একটি বাগ রিপোর্ট রয়েছে, যেহেতু কোডটি অন্য কেউ ওপিকে উপস্থাপন করেছে এবং সমস্ত কোড সি 2 বাগ ছাড়াই নেই (এটি এমনকি এর সাথে সম্পর্কিত হতে পারে)। আমি আশা করি এই বিশ্লেষণটি আমার কাছে যেমনটি ছিল তেমনি অন্যদের কাছে তথ্যবহুল ছিল।

শ্রদ্ধেয় অপাঙ্গিন মন্তব্যগুলিতে যেমন উল্লেখ করেছেন, এটি সাম্প্রতিক বাগ । আগ্রহী এবং সহায়ক সমস্ত লোকের কাছে অনেক বাধ্য :)

আশ্চর্যজনকভাবে, নিম্নলিখিত কোড আউটপুট:

/
-1

কোড:

public class LoopOutPut {

    public static void main(String[] args) {
        LoopOutPut loopOutPut = new LoopOutPut();
        for (int i = 0; i < 30000; i++) {
            loopOutPut.test();
        }

    }

    public void test() {
        int i = 8;
        while ((i -= 3) > 0) ;
        String value = i + "";
        if (!value.equals("-1")) {
            System.out.println(value);
            System.out.println(i);
        }
    }

}

এটি কতবার ঘটবে তা নির্ধারণ করার জন্য আমি বহুবার চেষ্টা করেছি, তবে, দুর্ভাগ্যক্রমে, এটি চূড়ান্তভাবে অনিশ্চিত ছিল এবং আমি খুঁজে পেয়েছিলাম যে -2 এর আউটপুট কখনও কখনও একটি সময়ের মধ্যে রূপান্তরিত হয়। তদতিরিক্ত, আমি কোনও সমস্যা ছাড়াই সময় লুপ এবং আউটপুট -1 অপসারণ করার চেষ্টা করেছি। কে আমাকে বলতে পারে কেন?

জেডিকে সংস্করণ তথ্য:

HopSpot 64-Bit 1.8.0.171
IDEA 2019.1.1

এটি সত্যই অদ্ভুত, কারণ সেই কোডটি প্রযুক্তিগতভাবে কখনও আউটপুট করা উচিত নয় কারণ ...

int i = 8;
while ((i -= 3) > 0);

... সর্বদা আমার ফলাফল -1 (8 - 3 = 5; 5 - 3 = 2; 2 - 3 = -1) হওয়া উচিত। এমনকি অদ্ভুত যেটি হ'ল এটি আমার আইডিইর ডিবাগ মোডে কখনই আউটপুট দেয় না।

মজার বিষয় হচ্ছে যে মুহুর্তে আমি একটি String রূপান্তরিত হওয়ার আগে একটি চেক যুক্ত করব, তারপরে কোনও সমস্যা নেই ...

public void test() {
  int i = 8;
  while ((i -= 3) > 0);
  if(i != -1) { System.out.println("Not -1"); }
  String value = String.valueOf(i);
  if (!"-1".equalsIgnoreCase(value)) {
    System.out.println(value);
    System.out.println(i);
  }
}

ভাল কোডিং অনুশীলনের মাত্র দুটি পয়েন্ট ...

  1. বরং String.valueOf() ব্যবহার করুন
  2. কিছু কোডিং স্ট্যান্ডার্ড নির্দিষ্ট করে যে স্ট্রিং .equals() যুক্তির চেয়ে বরং .equals() এর লক্ষ্য হওয়া উচিত, সুতরাং নালপয়েন্টারএক্সবেশনগুলি হ্রাস করা উচিত।

এটি না হওয়ার একমাত্র উপায় String.format() ব্যবহার করে

public void test() {
  int i = 8;
  while ((i -= 3) > 0);
  String value = String.format("%d", i);
  if (!"-1".equalsIgnoreCase(value)) {
    System.out.println(value);
    System.out.println(i);
  }
}

... মূলত দেখে মনে হচ্ছে জাভাটির নিঃশ্বাস ধরতে একটু সময় প্রয়োজন :)

সম্পাদনা: এটি পুরোপুরি কাকতালীয় হতে পারে তবে মুদ্রণকৃত মূল্য এবং ASCII সারণীর মধ্যে কিছুটা চিঠিপত্র বলে মনে হচ্ছে।

  • i = -1 , প্রদর্শিত অক্ষরটি হ'ল ((47 এর ASCII দশমিক মান))
  • i = -2 , অক্ষর প্রদর্শিত হয় . (46 এর ASCII দশমিক মান)
  • i = -3 , প্রদর্শিত অক্ষরটি হ'ল - (45 এর ASCII দশমিক মান)
  • i = -4 , অক্ষর প্রদর্শিত হয় , (44 এর ASCII দশমিক মান)
  • i = -5 , বর্ণিত অক্ষরটি + (এএসসিআইআই দশমিক মান 43)
  • i = -6 , অক্ষর প্রদর্শিত হয় * (ASCII দশমিক মান 42)
  • i = -7 , অক্ষর প্রদর্শিত হয় ) (41 এর ASCII দশমিক মান)
  • i = -8 , বর্ণিত অক্ষরটি ( 40 এর ASCII দশমিক মান)
  • i = -9 , প্রদর্শিত অক্ষরটি হল ' (39 এর ASCII দশমিক মান)

আসলেই আকর্ষণীয় বিষয়টি হ'ল ASCII দশমিক 48 এর অক্ষরটি 0 এবং 48 - 1 = 47 (অক্ষর / ) ইত্যাদি ...





jit