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


54

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

/
-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

2
মন্তব্যগুলি বর্ধিত আলোচনার জন্য নয়; এই কথোপকথন চ্যাটে সরানো হয়েছে ।
স্যামুয়েল লিউ

উত্তর:


36

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

আমি -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()দু'বার সংকলন করি । একবার শুরুর দিকে এবং তারপরে আবার (সম্ভবতঃ কারণটি পদ্ধতিটি কতটা গরম তা জেআইটি লক্ষ্য করে)। বগি এক্সিকিউশনটি 5 বার test()সংকলন করা হয় (বা পচনশীল) ।

অতিরিক্ত হিসাবে, -XX:-TieredCompilation(যা হয় ব্যাখ্যা করে, বা ব্যবহার করে C2) বা-Xbatch (যা সামঞ্জস্যের পরিবর্তে মূল থ্রেডে সংকলনকে চালিত করতে বাধ্য করে ) দিয়ে চলছে, আউটপুট গ্যারান্টিযুক্ত এবং 30000 পুনরাবৃত্তির সাহায্যে প্রচুর স্টাফ প্রিন্ট করে, তাই C2সংকলকটি মনে হয় অপরাধী হতে। এটি চালিয়ে -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 এর দশক থেকে আমার কাছে যে সামান্য সমাবেশ দক্ষতা রয়েছে তা তাই আমি আমার তুলনায় আরও চৌকস কাউকে নিতে দেব এখান থেকে.

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

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


আমি এটিও মনে করি C2- জিতওয়াচ ব্যবহার করে উত্পন্ন এসেম্বলারের কোডটি দেখেছি (এবং এটি বোঝার চেষ্টা করেছি) - C1উত্পন্ন কোডটি এখনও বাইটকোডের মতো দেখা যায়, C2সম্পূর্ণ আলাদা ( i8 এর সাথে আমি
আরম্ভও

আপনার উত্তরটি খুব ভাল, আমি চেষ্টা করেছি, সি 2 অক্ষম করেছি, ফলাফলটি সঠিক। তবে, সাধারণভাবে, এই পরামিতিগুলির বেশিরভাগটি প্রকল্পে ডিফল্ট হয় যদিও প্রকৃত প্রকল্পের উপরের কোডটি না থাকে তবে এটির অনুরূপ কোড হওয়ার সম্ভাবনা রয়েছে, যদি প্রকল্পটি অনুরূপ কোড ব্যবহার করে তবে তা সত্যই ভয়ঙ্কর
ওকলি

1
@ ইউজিন এটি বেশ জটিল ছিল, আমি নিশ্চিত ছিল যে এটি গ্রহগ্রাহের সংকলক বাগ বা অনুরূপ কিছু হতে চলেছে ... এবং আমি প্রথমে এটি পুনরুত্পাদন করতে পারিনি ..
কেয়ামান

1
@ কায়ামান তাতে রাজি হয়েছেন। আপনি যে বিশ্লেষণ করেছেন তা খুব ভাল, এটি বোঝাতে ও ঠিক করার জন্য অপাঙ্গিনের পক্ষে যথেষ্ট পরিমাণে হওয়া উচিত। ট্রেনে কী অসাধারণ সকাল!
ইউজিন

7
আমি এই বিষয়টি কেবল দুর্ঘটনাক্রমে লক্ষ্য করেছি। আমি প্রশ্নটি দেখেছি কিনা তা নিশ্চিত করতে @ উল্লেখগুলি ব্যবহার করুন বা একটি # জেভিএম ট্যাগ যুক্ত করুন। ভাল বিশ্লেষণ, বিটিডাব্লু। এটি প্রকৃতপক্ষে একটি সি 2 সংকলক বাগ, কিছু দিন আগে ঠিক করা হয়েছে - জেডিকে -8231988
অপাংগিন

4

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

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

... সর্বদা iহওয়ার ফল হওয়া উচিত -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()লিটারেলগুলি যুক্তির পরিবর্তে লক্ষ্য হওয়া উচিত , এভাবে নালপয়েন্টারএক্সবেশনগুলি হ্রাস করা উচিত।

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

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


1
তিনি "/" চরিত্রটির সংখ্যাগত মান "-1" ??? এটা কোথা থেকে আসে? ( (int)'/' == 47; (char)-1অনির্ধারিত হয় 0xFFFFহল <না একটি অক্ষর> ইউনিকোড মধ্যে)
user85421-নিষিদ্ধ

1
চর সি = '/'; int a = চরিত্র.গুণ সংখ্যাসম্য (গ); System.out.println (ক);
অ্যামব্রো আর

getNumericValue()প্রদত্ত কোডের সাথে কীভাবে সম্পর্কিত? এবং কিভাবে এটি রূপান্তরিত -1হয় '/'??? কেন না '-', getNumericValue('-')তাও -1??? ( -1
বিটিডব্লিউ অনেকগুলি

@CarlosHeuberger, আমি চলমান ছিল getNumericValue()উপর value( /) অক্ষর মান জন্য। আপনারা 100% সঠিক যে ASCII দশমিক মান /47 হওয়া উচিত (এটি আমিও প্রত্যাশা করছিলাম), তবে getNumericValue()আমি যুক্ত করার সাথে সাথে -1 ফিরছিলাম System.out.println(Character.getNumericValue(value.toCharArray()[0]));। আপনি যে বিভ্রান্তির কথা উল্লেখ করছেন এবং পোস্টটি আপডেট করেছেন তা আমি দেখতে পাচ্ছি।
অ্যামব্রো আর

1

জাভা কেন এমন এলোমেলো আউটপুট দিচ্ছে তা জানেন না তবে বিষয়টি আপনার সমালোচনার মধ্যে রয়েছে iযা forলুপের অভ্যন্তরে বৃহত্তর মানগুলির জন্য ব্যর্থ হয় ।

আপনি যদি আপনার কোডের String value = i + "";সাথে লাইন প্রতিস্থাপন String value = String.valueOf(i) ;করেন তবে প্রত্যাশার মতো কাজ করে।

ইন্টারে +স্ট্রিংয়ে রূপান্তর করতে ব্যবহার করে কনটেনটেশন স্থানীয় এবং এটি বগি হতে পারে (অদ্ভুতভাবে আমরা এখন এটি সম্ভবত খুঁজে পাচ্ছি) এবং এ জাতীয় সমস্যা সৃষ্টি করে।

দ্রষ্টব্য: আমি লুপের জন্য আমার অভ্যন্তরের মানকে 10000 এ কমিয়ে দিয়েছি এবং আমি +কনকনেটেশনের সাথে সমস্যার মুখোমুখি হই না ।

এই সমস্যাটি অবশ্যই জাভা সংশ্লিষ্টদের কাছে জানাতে হবে এবং তারাও তাদের মতামত দিতে পারে।

সম্পাদনা আমি লুপের জন্য i এর মান 3 মিলিয়নে আপডেট করেছি এবং নীচের মতো নতুন সেট ত্রুটি দেখেছি:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
    at java.lang.Integer.getChars(Integer.java:463)
    at java.lang.Integer.toString(Integer.java:402)
    at java.lang.String.valueOf(String.java:3099)
    at solving.LoopOutPut.test(LoopOutPut.java:16)
    at solving.LoopOutPut.main(LoopOutPut.java:8)

আমার জাভা ভার্সন 8।


1
আমি মনে করি না যে স্ট্রিং কনটেনটেশনটি দেশীয় - এটি কেবল StringConcatFactory(ওপেনজেডকে 13) বা StringBuilder(জাভা 8)
ব্যবহারকারী 85421-নিষিদ্ধ

@ কার্লোস হিউবার্গারও সম্ভব আমি মনে করি এটি জাভা 9 থেকে এসেছে যদি এটির StringConcatFactory শ্রেণি হতে হয় । তবে যতদূর আমি জাভা 8 টা জাভা ডন পর্যন্ত জানে না; টি অপারেটর ওভারলোডিং সমর্থন করে না
বিনয় প্রজাপতি

@ ভিনয়ে, এটিও চেষ্টা করে দেখুন এবং হ্যাঁ এটি কাজ করে তবে আপনি যে সমস্যাটি 30000 থেকে 3000000 এ বাড়িয়েছেন তা বলতে গেলে আপনার একই সমস্যাটি শুরু হয়।
অ্যামব্রো আর

@ অ্যামব্রো-আর আমি আপনার প্রস্তাবিত মানটি দিয়ে চেষ্টা করেছি এবং আমি Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1ত্রুটি পেয়েছি । স্ট্রেঞ্জ।
বিনয় প্রজাপতি

3
i + ""new StringBuilder().append(i).append("").toString()জাভা 8-তে ঠিক যেমনটি সংকলিত হয়েছে , এবং এটি ব্যবহার করে অবশেষে
আউটপুটও
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.