ব্যতিক্রম নিক্ষেপের কোন অংশটি ব্যয়বহুল?


256

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

আমার প্রশ্নটি হল, থ্রো / ক্যাচ নিজেই ব্যয় করে বা ব্যতিক্রমী বস্তু তৈরি করার সময় (যেহেতু এটি এক্সিকিউশন স্ট্যাক সহ প্রচুর রানটাইম তথ্য পায়)?

অন্য কথায়, আমি যদি না

Exception e = new Exception();

তবে এটি ফেলে দিন না, এটিই বেশিরভাগ নিক্ষেপ ব্যয়, বা নিক্ষেপ + কী ব্যয়বহুল তা পরিচালনা করছে?

আমি চেষ্টা করছি না / কোড ব্লকে কোড লাগানো সেই কোডটি কার্যকর করার ব্যয়কে যুক্ত করে কিনা জিজ্ঞাসা করছি না, ব্যতিক্রমটি ধরা ব্যয়বহুল অংশ কিনা, বা তৈরির জন্য (কনস্ট্রাক্টরকে ফোন করা) ব্যয় ব্যয়বহুল অংশ কিনা তা আমি জিজ্ঞাসা করছি ।

এটি জিজ্ঞাসার আরেকটি উপায় হ'ল, যদি আমি ব্যতিক্রমের একটি উদাহরণ তৈরি করি এবং তা ছুঁড়ে মারি এবং বারবার ধরে ফেলেছি, তবে প্রতিবার নিক্ষেপ করে নতুন ব্যতিক্রম তৈরি করার চেয়ে তা কি দ্রুততর হবে?


20
আমি বিশ্বাস করি এটি স্ট্যাক ট্রেসটি পূরণ করছে এবং পপুলেট করছে।
এলিয়ট ফ্রিচ


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

2
@ শেমো আমি কোডে আসলে এটি করার পরিকল্পনা করি না , আমি পারফরম্যান্স সম্পর্কে জিজ্ঞাসা করছি এবং এই উদাসীনতাটিকে উদাহরণ হিসাবে ব্যবহার করছি যেখানে এটি কোনও পার্থক্য করতে পারে।
মার্টিন কার্নে 21 '

@ মার্টিনকার্নি আমি আপনার শেষ অনুচ্ছেদে একটি উত্তর যুক্ত করেছি অর্থাত্ একটি ব্যতিক্রমীকরণের ক্যাশে হবে পারফরম্যান্স লাভ। যদি এটি দরকারী হয় তবে আমি কোডটি যুক্ত করতে পারি, না হলে আমি উত্তরটি মুছতে পারি।
হ্যারি

উত্তর:


267

তৈরি করা হচ্ছে একটি ব্যতিক্রম বস্তুর অন্যান্য নিয়মিত বস্তু তৈরি বেশী ব্যয়বহুল নয়। মূল ব্যয়টি দেশীয় fillInStackTraceপদ্ধতিতে লুকানো থাকে যা কল স্ট্যাকের মধ্য দিয়ে চলে এবং স্ট্যাক ট্রেস তৈরি করতে প্রয়োজনীয় তথ্য সংগ্রহ করে: শ্রেণি, পদ্ধতির নাম, লাইন নম্বর ইত্যাদি etc.

উচ্চ ব্যতিক্রম সংক্রান্ত ব্যয় সম্পর্কে মিথটি প্রচলিত রয়েছে যে বেশিরভাগ Throwableনির্মাতাকে সুস্পষ্টভাবে কল করে fillInStackTrace। তবে, স্ট্যাক ট্রেস ছাড়াই একটি তৈরির জন্য একজন কনস্ট্রাক্টর রয়েছেThrowable । এটি আপনাকে তাত্ক্ষণিকভাবে দ্রুত যা দ্রুতগতিতে তৈরি করতে দেয়। লাইটওয়েট ব্যতিক্রম তৈরি করার আরেকটি উপায় হ'ল ওভাররাইড fillInStackTrace


এখন ব্যতিক্রম ছোঁড়া সম্পর্কে কি ?
প্রকৃতপক্ষে, এটি যেখানে নিক্ষিপ্ত ব্যতিক্রম ধরা পড়ে তার উপর নির্ভর করে ।

যদি এটি একই পদ্ধতিতে ধরা পড়ে (বা, আরও সুনির্দিষ্টভাবে, একই প্রসঙ্গে, যেহেতু প্রসঙ্গটি ইনলাইনিংয়ের কারণে বেশ কয়েকটি পদ্ধতি অন্তর্ভুক্ত করতে পারে), তবে throwএটি goto(জেআইটি সংকলনের পরে) অবশ্যই তত দ্রুত এবং সহজ ।

তবে যদি কোনও catchব্লক স্ট্যাকের কোথাও গভীর হয়, তবে জেভিএমকে স্ট্যাকের ফ্রেমগুলি খোলার দরকার হয় এবং এটি উল্লেখযোগ্যভাবে আরও বেশি সময় নিতে পারে। এটিতে আরও বেশি সময় লাগে, যদি সেখানে synchronizedব্লক বা পদ্ধতি জড়িত থাকে, কারণ অযাচিতভাবে মুছে ফেলা স্ট্যাক ফ্রেমের মালিকানাধীন মনিটরদের মুক্তি দেওয়া বোঝায়।


আমি উপরের বক্তব্যগুলি যথাযথ মাপদণ্ডের দ্বারা নিশ্চিত করতে পারি, তবে সৌভাগ্যক্রমে আমার এটি করার দরকার নেই, যেহেতু হটস্পটের পারফরম্যান্স ইঞ্জিনিয়ার আলেক্সি শিপিলিভের পোস্টটিতে সমস্ত দিক ইতিমধ্যে পুরোপুরিভাবে আবৃত রয়েছে: লিল 'ব্যতিক্রমের ব্যতিক্রমী পারফরম্যান্স'


8
যেমন নিবন্ধে উল্লিখিত এবং এখানে স্পর্শ করা হয়েছে, আপশটটি হ'ল ব্যতিক্রম ছোঁড়া / ধরা ব্যয় কলগুলির গভীরতার উপর অত্যন্ত নির্ভরশীল। এখানে বক্তব্যটি হ'ল "ব্যতিক্রম ব্যয়বহুল" বিবৃতিটি সত্যই সঠিক নয়। আরও সঠিক বিবৃতিটি হল ব্যতিক্রমগুলি ব্যয়বহুল হতে পারে। সত্যিই, আমি মনে করি কেবল "সত্যিকারের ব্যতিক্রমী কেস" (নিবন্ধের মতো) এর জন্য কেবল ব্যতিক্রমগুলি ব্যবহার করা খুব দৃ strongly়ভাবে শব্দযুক্ত। এগুলি স্বাভাবিক রিটার্ন প্রবাহের বাইরে বেশ কিছু কিছুর জন্য নিখুঁত এবং এগুলি সত্যিকারের প্রয়োগে এইভাবে ব্যবহারের পারফরম্যান্স প্রভাব সনাক্ত করা শক্ত।
জিমি জেমস

14
ব্যতিক্রমগুলির ওভারহেড পরিমাণ করা এটি মূল্যবান হতে পারে। এমনকি এটি অত্যন্ত বিবর্ধনীয় নিবন্ধে রিপোর্ট করা (স্ট্যাকট্রেস যা আসলে জিজ্ঞাসিত, 1000 স্ট্যাক ফ্রেমের গভীর গভীরতার সাথে একটি গতিশীল ব্যতিক্রম ছুঁড়ে ফেলা এবং ধরা) 80 মাইক্রো সেকেন্ড সময় নেয়। এটি তাত্পর্যপূর্ণ হতে পারে যদি আপনার সিস্টেমে প্রতি সেকেন্ডে কয়েক হাজার ব্যতিক্রম প্রক্রিয়া করা প্রয়োজন তবে অন্যথায় উদ্বিগ্ন হওয়ার মতো নয়। এবং এটি সবচেয়ে খারাপ পরিস্থিতি; যদি আপনার স্ট্যাকট্রেসগুলি সামান্য স্যানার হয়, বা আপনি তাদের স্ট্যাকট্রেস অনুসন্ধান করেন না, তবে আমরা প্রতি সেকেন্ডে প্রায় মিলিয়ন ব্যতিক্রম প্রক্রিয়া করতে পারি।
মেরিটন

13
আমি এটি জোর দিয়েছি কারণ অনেক লোক, ব্যতিক্রমগুলি "ব্যয়বহুল" পড়ার পরে কখনও "কিসের তুলনায় ব্যয়বহুল" জিজ্ঞাসা করা বন্ধ করে না, তবে তারা "তাদের প্রোগ্রামের ব্যয়বহুল অংশ", যা তারা খুব কমই বলে মনে করে।
মেরিটন

2
এখানে একটি অংশ উল্লেখ করা হয়নি: অপ্টিমাইজেশন প্রয়োগ করা থেকে রোধ করার সম্ভাব্য ব্যয়। একটি চূড়ান্ত উদাহরণ হ'ল জেভিএম "জঞ্জাল" স্ট্যাকের চিহ্নগুলি এড়ানোর জন্য অন্তর্নিহিত নয়, তবে আমি (মাইক্রো) বেঞ্চমার্কগুলি দেখেছি যেখানে ব্যতিক্রমের উপস্থিতি বা অনুপস্থিতি সি ++ এর আগে অপ্টিমাইজেশান তৈরি করবে বা ভাঙবে।
ম্যাথিউ এম।

3
@MatthieuM। ব্যতিক্রম এবং চেষ্টা / ব্লকগুলি ব্লকগুলি জেভিএমকে ইনলাইন করা থেকে বাধা দেয় না। সংকলিত পদ্ধতির জন্য প্রকৃত স্ট্যাকের চিহ্নগুলি মেটাডেটা হিসাবে সঞ্চিত ভার্চুয়াল স্ট্যাক ফ্রেম টেবিল থেকে পুনর্গঠন করা হয়। আমি কোনও জেআইটি অপটিমাইজেশন স্মরণ করতে পারছি না যা চেষ্টা / ধরার সাথে বেমানান। চেষ্টা করুন / ক্যাচ স্ট্রাকচার নিজেই পদ্ধতি কোডে কিছু যোগ করে না, এটি কোড থেকে বাদে কেবলমাত্র একটি ব্যতিক্রম টেবিল হিসাবে বিদ্যমান।
আপানগিন

72

বেশিরভাগ Throwableকনস্ট্রাক্টরের প্রথম ক্রিয়াকলাপটি স্ট্যাক ট্রেস পূরণ করা হয়, যেখানে বেশিরভাগ ব্যয় হয়।

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

আপনি যদি সাধারণ উপায়ে যে কোনও ধরণের একক ব্যতিক্রম তৈরি করেন তবে স্ট্যাকের ট্রেস পূরণ না করে আপনি ওভারহেড ছাড়াই বহুবার এটিকে আবার ফেলে দিতে পারেন। তবে, এটির স্ট্যাক ট্রেস প্রতিফলিত করবে যেখানে এটি নির্মিত হয়েছিল, যেখানে এটি কোনও নির্দিষ্ট ক্ষেত্রে নিক্ষেপ করা হয়েছিল not

জাভার বর্তমান সংস্করণগুলি স্ট্যাক ট্রেস তৈরির অনুকূলকরণের জন্য কিছু চেষ্টা করে। নেটিভ কোডটি স্ট্যাক ট্রেস পূরণ করার জন্য আহ্বান জানানো হয়েছে, যা হালকা ওজন, নেটিভ কাঠামোতে ট্রেস রেকর্ড করে। সংশ্লিষ্ট জাভা StackTraceElementবস্তু প্রখর রৌদ্রে এই রেকর্ড শুধুমাত্র যখন থেকে তৈরি করা হয় getStackTrace(), printStackTrace()বা অন্যান্য পদ্ধতি ট্রেস প্রয়োজন বলা হয়।

যদি আপনি স্ট্যাক ট্রেস প্রজন্মকে সরিয়ে দেন, তবে অন্য প্রধান ব্যয়টি স্ট্রোকটি এবং ক্যাচের মধ্যে সরিয়ে আনতে হবে। ব্যতিক্রম ধরা পড়ার আগে যত কম হস্তক্ষেপযুক্ত ফ্রেমগুলির মুখোমুখি হয়েছিল, এটি তত দ্রুত হবে।

আপনার প্রোগ্রামটি ডিজাইন করুন যাতে ব্যতিক্রমগুলি কেবল সত্যিকারের ব্যতিক্রমী ক্ষেত্রে ফেলে দেওয়া হয় এবং এর মতো অপ্টিমাইজেশানগুলি ন্যায়সঙ্গত হওয়া শক্ত।


3
কনস্ট্রাক্টরের সাথে লিঙ্ক করুন: ডকস.অরাকল.com

25

এখানে ব্যতিক্রম একটি ভাল লেখার আছে।

http://shipilev.net/blog/2014/exceptional-performance/

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

নিচে একা অবজেক্ট তৈরির সময় রয়েছে tim আমি Stringএখানে যুক্ত করেছি যাতে আপনি দেখতে পারেন যে স্ট্যাকটি লিখিত না থাকলে কোনও JavaExceptionঅবজেক্ট এবং ক তৈরির ক্ষেত্রে প্রায় কোনও পার্থক্য নেই String। স্ট্যাক রাইটিংটি পার্থক্যটি চালু করার সাথে নাটকীয় অর্থাৎ কমপক্ষে কমপক্ষে একটি ক্রমের মান কমিয়ে দেওয়া হয়।

Time to create million String objects: 41.41 (ms)
Time to create million JavaException objects with    stack: 608.89 (ms)
Time to create million JavaException objects without stack: 43.50 (ms)

নিম্নলিখিতটি দেখায় যে একটি নির্দিষ্ট গভীরতায় এক মিলিয়ন বার কোনও নিক্ষেপ থেকে ফিরে আসতে কতক্ষণ সময় লেগেছে।

|Depth| WriteStack(ms)| !WriteStack(ms)| Diff(%)|
|   16|           1428|             243| 588 (%)|
|   15|           1763|             393| 449 (%)|
|   14|           1746|             390| 448 (%)|
|   13|           1703|             384| 443 (%)|
|   12|           1697|             391| 434 (%)|
|   11|           1707|             410| 416 (%)|
|   10|           1226|             197| 622 (%)|
|    9|           1242|             206| 603 (%)|
|    8|           1251|             207| 604 (%)|
|    7|           1213|             208| 583 (%)|
|    6|           1164|             206| 565 (%)|
|    5|           1134|             205| 553 (%)|
|    4|           1106|             203| 545 (%)|
|    3|           1043|             192| 543 (%)| 

নীচেরটি প্রায় সরলীকরণের তুলনায় অবশ্যই একটি স্থূল ...

যদি আমরা স্ট্যাক রাইটিং দিয়ে 16 এর গভীরতা নিয়ে যাই তবে অবজেক্ট তৈরিতে সময় প্রায় 40% ডলার লাগবে, প্রকৃত স্ট্যাকটি এর বিশাল অংশের জন্য খাঁটি। Java 93% জাভেক্সিপশন অবজেক্টটি তাত্ক্ষণিকভাবে স্ট্যাকের সন্ধানের কারণে নেওয়া হয়েছে। এর অর্থ হল যে এই ক্ষেত্রে স্ট্যাকটি আনওয়াইন্ডিং করা হচ্ছে অন্যান্য 50% সময় নিচ্ছে is

যখন আমরা স্ট্যাক ট্রেস অবজেক্ট তৈরির অ্যাকাউন্টগুলিকে অনেক ছোট ভগ্নাংশের জন্য অর্থাৎ 20% এবং স্ট্যাক আনওয়াইন্ডিং বন্ধ করে দিই তখন সময়ের 80% হয়।

উভয় ক্ষেত্রে স্ট্যাক আনওয়াইন্ডিং সামগ্রিক সময়ের একটি বড় অংশ নেয়।

public class JavaException extends Exception {
  JavaException(String reason, int mode) {
    super(reason, null, false, false);
  }
  JavaException(String reason) {
    super(reason);
  }

  public static void main(String[] args) {
    int iterations = 1000000;
    long create_time_with    = 0;
    long create_time_without = 0;
    long create_string = 0;
    for (int i = 0; i < iterations; i++) {
      long start = System.nanoTime();
      JavaException jex = new JavaException("testing");
      long stop  =  System.nanoTime();
      create_time_with += stop - start;

      start = System.nanoTime();
      JavaException jex2 = new JavaException("testing", 1);
      stop = System.nanoTime();
      create_time_without += stop - start;

      start = System.nanoTime();
      String str = new String("testing");
      stop = System.nanoTime();
      create_string += stop - start;

    }
    double interval_with    = ((double)create_time_with)/1000000;
    double interval_without = ((double)create_time_without)/1000000;
    double interval_string  = ((double)create_string)/1000000;

    System.out.printf("Time to create %d String objects: %.2f (ms)\n", iterations, interval_string);
    System.out.printf("Time to create %d JavaException objects with    stack: %.2f (ms)\n", iterations, interval_with);
    System.out.printf("Time to create %d JavaException objects without stack: %.2f (ms)\n", iterations, interval_without);

    JavaException jex = new JavaException("testing");
    int depth = 14;
    int i = depth;
    double[] with_stack    = new double[20];
    double[] without_stack = new double[20];

    for(; i > 0 ; --i) {
      without_stack[i] = jex.timerLoop(i, iterations, 0)/1000000;
      with_stack[i]    = jex.timerLoop(i, iterations, 1)/1000000;
    }
    i = depth;
    System.out.printf("|Depth| WriteStack(ms)| !WriteStack(ms)| Diff(%%)|\n");
    for(; i > 0 ; --i) {
      double ratio = (with_stack[i] / (double) without_stack[i]) * 100;
      System.out.printf("|%5d| %14.0f| %15.0f| %2.0f (%%)| \n", i + 2, with_stack[i] , without_stack[i], ratio);
      //System.out.printf("%d\t%.2f (ms)\n", i, ratio);
    }
  }
 private int thrower(int i, int mode) throws JavaException {
    ExArg.time_start[i] = System.nanoTime();
    if(mode == 0) { throw new JavaException("without stack", 1); }
    throw new JavaException("with stack");
  }
  private int catcher1(int i, int mode) throws JavaException{
    return this.stack_of_calls(i, mode);
  }
  private long timerLoop(int depth, int iterations, int mode) {
    for (int i = 0; i < iterations; i++) {
      try {
        this.catcher1(depth, mode);
      } catch (JavaException e) {
        ExArg.time_accum[depth] += (System.nanoTime() - ExArg.time_start[depth]);
      }
    }
    //long stop = System.nanoTime();
    return ExArg.time_accum[depth];
  }

  private int bad_method14(int i, int mode) throws JavaException  {
    if(i > 0) { this.thrower(i, mode); }
    return i;
  }
  private int bad_method13(int i, int mode) throws JavaException  {
    if(i == 13) { this.thrower(i, mode); }
    return bad_method14(i,mode);
  }
  private int bad_method12(int i, int mode) throws JavaException{
    if(i == 12) { this.thrower(i, mode); }
    return bad_method13(i,mode);
  }
  private int bad_method11(int i, int mode) throws JavaException{
    if(i == 11) { this.thrower(i, mode); }
    return bad_method12(i,mode);
  }
  private int bad_method10(int i, int mode) throws JavaException{
    if(i == 10) { this.thrower(i, mode); }
    return bad_method11(i,mode);
  }
  private int bad_method9(int i, int mode) throws JavaException{
    if(i == 9) { this.thrower(i, mode); }
    return bad_method10(i,mode);
  }
  private int bad_method8(int i, int mode) throws JavaException{
    if(i == 8) { this.thrower(i, mode); }
    return bad_method9(i,mode);
  }
  private int bad_method7(int i, int mode) throws JavaException{
    if(i == 7) { this.thrower(i, mode); }
    return bad_method8(i,mode);
  }
  private int bad_method6(int i, int mode) throws JavaException{
    if(i == 6) { this.thrower(i, mode); }
    return bad_method7(i,mode);
  }
  private int bad_method5(int i, int mode) throws JavaException{
    if(i == 5) { this.thrower(i, mode); }
    return bad_method6(i,mode);
  }
  private int bad_method4(int i, int mode) throws JavaException{
    if(i == 4) { this.thrower(i, mode); }
    return bad_method5(i,mode);
  }
  protected int bad_method3(int i, int mode) throws JavaException{
    if(i == 3) { this.thrower(i, mode); }
    return bad_method4(i,mode);
  }
  private int bad_method2(int i, int mode) throws JavaException{
    if(i == 2) { this.thrower(i, mode); }
    return bad_method3(i,mode);
  }
  private int bad_method1(int i, int mode) throws JavaException{
    if(i == 1) { this.thrower(i, mode); }
    return bad_method2(i,mode);
  }
  private int stack_of_calls(int i, int mode) throws JavaException{
    if(i == 0) { this.thrower(i, mode); }
    return bad_method1(i,mode);
  }
}

class ExArg {
  public static long[] time_start;
  public static long[] time_accum;
  static {
     time_start = new long[20];
     time_accum = new long[20];
  };
}

এই উদাহরণের স্ট্যাক ফ্রেমগুলি আপনি সাধারণত যা খুঁজে পাবেন তার তুলনায় খুব ছোট।

জাভাপ ব্যবহার করে আপনি বাইটকোডে উঁকি দিতে পারেন

javap -c -v -constants JavaException.class

অর্থাৎ এটি পদ্ধতি 4 এর জন্য ...

   protected int bad_method3(int, int) throws JavaException;
flags: ACC_PROTECTED
Code:
  stack=3, locals=3, args_size=3
     0: iload_1       
     1: iconst_3      
     2: if_icmpne     12
     5: aload_0       
     6: iload_1       
     7: iload_2       
     8: invokespecial #6                  // Method thrower:(II)I
    11: pop           
    12: aload_0       
    13: iload_1       
    14: iload_2       
    15: invokespecial #17                 // Method bad_method4:(II)I
    18: ireturn       
  LineNumberTable:
    line 63: 0
    line 64: 12
  StackMapTable: number_of_entries = 1
       frame_type = 12 /* same */

Exceptions:
  throws JavaException

13

স্ট্যাক ট্রেস Exceptionসহ এর তৈরিতে nullযতটা সময় লাগে throwএবং try-catchএকসাথে অবরুদ্ধ হয়। তবে, স্ট্যাকের ট্রেসটি পূরণ করতে গড়ে 5x দীর্ঘ সময় লাগে

পারফরম্যান্সের প্রভাবটি প্রদর্শন করতে আমি নীচের মানদণ্ড তৈরি করেছি। -Djava.compiler=NONEসংকলক অপ্টিমাইজেশন অক্ষম করতে রান কনফিগারেশনে আমি যুক্ত করেছি । স্ট্যাক ট্রেস নির্মাণের প্রভাব পরিমাপ করতে, Exceptionস্ট্যাক-মুক্ত নির্মাণকারীর সুবিধা নেওয়ার জন্য আমি ক্লাসটি বাড়িয়েছি :

class NoStackException extends Exception{
    public NoStackException() {
        super("",null,false,false);
    }
}

মানদণ্ডের কোডটি নিম্নরূপ:

public class ExceptionBenchmark {

    private static final int NUM_TRIES = 100000;

    public static void main(String[] args) {

        long throwCatchTime = 0, newExceptionTime = 0, newObjectTime = 0, noStackExceptionTime = 0;

        for (int i = 0; i < 30; i++) {
            throwCatchTime += throwCatchLoop();
            newExceptionTime += newExceptionLoop();
            newObjectTime += newObjectLoop();
            noStackExceptionTime += newNoStackExceptionLoop();
        }

        System.out.println("throwCatchTime = " + throwCatchTime / 30);
        System.out.println("newExceptionTime = " + newExceptionTime / 30);
        System.out.println("newStringTime = " + newObjectTime / 30);
        System.out.println("noStackExceptionTime = " + noStackExceptionTime / 30);

    }

    private static long throwCatchLoop() {
        Exception ex = new Exception(); //Instantiated here
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            try {
                throw ex; //repeatedly thrown
            } catch (Exception e) {

                // do nothing
            }
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long newExceptionLoop() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            Exception e = new Exception();
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long newObjectLoop() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            Object o = new Object();
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long newNoStackExceptionLoop() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            NoStackException e = new NoStackException();
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

}

আউটপুট:

throwCatchTime = 19
newExceptionTime = 77
newObjectTime = 3
noStackExceptionTime = 15

এটি বোঝায় যে একটি তৈরি NoStackExceptionকরা প্রায় একই বার বার ছুঁড়ে ফেলার মতো ব্যয়বহুল Exception। এটি আরও দেখায় যে এটি তৈরি Exceptionএবং এর স্ট্যাক ট্রেস পূরণ করতে প্রায় 4x বেশি সময় লাগে ।


1
আপনি কি আর একটি কেস যুক্ত করতে পারেন যেখানে আপনি শুরুর আগে একটি ব্যতিক্রম উদাহরণ তৈরি করেন, তারপরে + বার বার লুপে ফেলে দিন? এটি কেবল ছোঁড়া + ধরার ব্যয় দেখায়।
মার্টিন কার্নে

@ মার্টিনকার্নি দুর্দান্ত পরামর্শ! আমি ঠিক তা করতে আমার উত্তর আপডেট করেছি।
অস্টিন ডি

আমি আপনার পরীক্ষার কোডটির জন্য কিছু টুইট করেছি এবং দেখে মনে হচ্ছে যে সংকলকটি কিছু অপ্টিমাইজেশন করছে যা আমাদের সঠিক সংখ্যা পেতে বাধা দেয়।
মার্টিন কার্নে 21

@ মার্টিনকার্নি আমি ডিসকাউন্ট সংকলন অপ্টিমাইজেশনের উত্তর আপডেট করেছি
অস্টিন ডি

এফওয়াইআই, আপনার সম্ভবত উত্তরগুলি পড়া উচিত জাভাতে আমি কীভাবে একটি সঠিক মাইক্রো-বেঞ্চমার্ক লিখি? ইঙ্গিত: এটি না।
ড্যানিয়েল প্রাইডেন

4

প্রশ্নের এই অংশ ...

এটি জিজ্ঞাসার আরেকটি উপায় হ'ল, যদি আমি ব্যতিক্রমের একটি উদাহরণ তৈরি করি এবং তা ছুঁড়ে মারি এবং বারবার ধরে ফেলেছি, তবে প্রতিবার নিক্ষেপ করে নতুন ব্যতিক্রম তৈরি করার চেয়ে তা কি দ্রুততর হবে?

মনে হয় কোনও ব্যতিক্রম তৈরি করে এবং এটি কোথাও ক্যাশে করলে কর্মক্ষমতা উন্নত হয় কিনা জিজ্ঞাসা করছে asking হ্যাঁ এটা করে. এটি বস্তু তৈরিতে লেখা স্ট্যাকটি বন্ধ করার সমান কারণ এটি ইতিমধ্যে হয়ে গেছে।

এই সময় আমি পেয়েছি, অনুগ্রহ করে এর পরে সাবধানতা পড়ুন ...

|Depth| WriteStack(ms)| !WriteStack(ms)| Diff(%)|
|   16|            193|             251| 77 (%)| 
|   15|            390|             406| 96 (%)| 
|   14|            394|             401| 98 (%)| 
|   13|            381|             385| 99 (%)| 
|   12|            387|             370| 105 (%)| 
|   11|            368|             376| 98 (%)| 
|   10|            188|             192| 98 (%)| 
|    9|            193|             195| 99 (%)| 
|    8|            200|             188| 106 (%)| 
|    7|            187|             184| 102 (%)| 
|    6|            196|             200| 98 (%)| 
|    5|            197|             193| 102 (%)| 
|    4|            198|             190| 104 (%)| 
|    3|            193|             183| 105 (%)| 

অবশ্যই এটির সাথে সমস্যা হ'ল এখন আপনার স্ট্যাক ট্রেসটি ইঙ্গিত করে যেখানে আপনি বস্তুটি কোথা থেকে ছুঁড়েছিলেন তা নয় inst


3

@ অস্টিনডির উত্তরটি একটি সূচনা পয়েন্ট হিসাবে ব্যবহার করে, আমি কিছু টুইট করেছি। নীচে কোড।

একটি ব্যতিক্রম উদাহরণ বারবার নিক্ষেপ করা হয় সেই ক্ষেত্রে কেস যোগ করার পাশাপাশি আমি সংকলক অপ্টিমাইজেশনও বন্ধ করে দিয়েছি যাতে আমরা সঠিক পারফরম্যান্সের ফলাফল পেতে পারি। আমি এই উত্তর-Djava.compiler=NONE হিসাবে ভিএম যুক্তি যুক্ত করেছি । (গ্রহণে, এই ভিএম যুক্তিটি সেট করার জন্য রান কনফিগারেশন → যুক্তিগুলি সম্পাদনা করুন)

ফলাফলগুলো:

new Exception + throw/catch = 643.5
new Exception only          = 510.7
throw/catch only            = 115.2
new String (benchmark)      = 669.8

সুতরাং ব্যতিক্রমটি তৈরি করতে প্রায় 5x প্রায় ছোঁড়া + ধরা এটির মতো ব্যয় হয়। সংকলক ধরে নিলে ব্যয়ের বেশিরভাগই অপ্টিমাইজ হয় না।

তুলনার জন্য, অপ্টিমাইজেশন অক্ষম না করে এখানে একই পরীক্ষাটি চালানো হচ্ছে:

new Exception + throw/catch = 382.6
new Exception only          = 379.5
throw/catch only            = 0.3
new String (benchmark)      = 15.6

কোড:

public class ExceptionPerformanceTest {

    private static final int NUM_TRIES = 1000000;

    public static void main(String[] args) {

        double numIterations = 10;

        long exceptionPlusCatchTime = 0, excepTime = 0, strTime = 0, throwTime = 0;

        for (int i = 0; i < numIterations; i++) {
            exceptionPlusCatchTime += exceptionPlusCatchBlock();
            excepTime += createException();
            throwTime += catchBlock();
            strTime += createString();
        }

        System.out.println("new Exception + throw/catch = " + exceptionPlusCatchTime / numIterations);
        System.out.println("new Exception only          = " + excepTime / numIterations);
        System.out.println("throw/catch only            = " + throwTime / numIterations);
        System.out.println("new String (benchmark)      = " + strTime / numIterations);

    }

    private static long exceptionPlusCatchBlock() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            try {
                throw new Exception();
            } catch (Exception e) {
                // do nothing
            }
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long createException() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            Exception e = new Exception();
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long createString() {
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            Object o = new String("" + i);
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }

    private static long catchBlock() {
        Exception ex = new Exception(); //Instantiated here
        long start = System.currentTimeMillis();
        for (int i = 0; i < NUM_TRIES; i++) {
            try {
                throw ex; //repeatedly thrown
            } catch (Exception e) {
                // do nothing
            }
        }
        long stop = System.currentTimeMillis();
        return stop - start;
    }
}

অপ্টিমাইজেশন অক্ষম করা = দুর্দান্ত কৌশল! আমি আমার আসল উত্তরটি সম্পাদনা করব যাতে কাউকে বিভ্রান্ত না করে
অস্টিন ডি

3
ত্রুটিযুক্ত বেঞ্চমার্ক লেখার চেয়ে অপ্টিমাইজেশন অক্ষম করা কোনওভাবেই ভাল নয়, যেহেতু খাঁটি ইন্টারপ্রিটেড মোডের বাস্তব-বিশ্বের পারফরম্যান্সের সাথে কোনও সম্পর্ক নেই। জেভিএমের শক্তিটি হ'ল জেআইটি সংকলক, সুতরাং এমন কিছু পরিমাপ করার কী আছে যা বাস্তব প্রয়োগের কাজটিকে প্রতিফলিত করে না?
অপাঙ্গীন

2
এই 'বেঞ্চমার্ক'-এ প্রকাশিত হওয়ার চেয়ে ব্যতিক্রমগুলি তৈরি, নিক্ষেপ এবং ধরার আরও অনেক দিক রয়েছে। আমি আপনাকে দৃ strongly়ভাবে এই পোস্ট পড়তে পরামর্শ দিচ্ছি ।
অপাঙ্গিন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.