জাভা প্রতিবিম্ব কর্মক্ষমতা


172

ক্লাস কনস্ট্রাক্টরকে কল করার পরিবর্তে প্রতিফলন ব্যবহার করে কোনও অবজেক্ট তৈরি করা কি কোনও উল্লেখযোগ্য পারফরম্যান্সের পার্থক্যের ফলে?


উত্তর:


169

অবশ্যই হ্যাঁ. প্রতিবিম্বের মাধ্যমে একটি শ্রেণীর সন্ধান করা, প্রস্থের দ্বারা , আরও ব্যয়বহুল।

প্রতিবিম্বের উপর জাভার ডকুমেন্টেশন উদ্ধৃত :

যেহেতু প্রতিচ্ছবিতে এমন প্রকারগুলি অন্তর্ভুক্ত থাকে যা গতিশীলভাবে সমাধান করা হয়, কিছু জাভা ভার্চুয়াল মেশিন অপ্টিমাইজেশান সম্পাদন করা যায় না। ফলস্বরূপ, প্রতিফলিত অপারেশনগুলির তাদের অ-প্রতিবিম্বিত অংশগুলির তুলনায় ধীর পারফরম্যান্স থাকে এবং কোডের এমন কিছু অংশে এড়ানো উচিত যা কর্মক্ষমতা-সংবেদনশীল অ্যাপ্লিকেশনগুলিতে প্রায়শই বলা হয়।

সান জেআরই 6u10 চালিয়ে আমি আমার মেশিনে 5 মিনিটের মধ্যে হ্যাক করেছিলাম এমন একটি সহজ পরীক্ষা:

public class Main {

    public static void main(String[] args) throws Exception
    {
        doRegular();
        doReflection();
    }

    public static void doRegular() throws Exception
    {
        long start = System.currentTimeMillis();
        for (int i=0; i<1000000; i++)
        {
            A a = new A();
            a.doSomeThing();
        }
        System.out.println(System.currentTimeMillis() - start);
    }

    public static void doReflection() throws Exception
    {
        long start = System.currentTimeMillis();
        for (int i=0; i<1000000; i++)
        {
            A a = (A) Class.forName("misc.A").newInstance();
            a.doSomeThing();
        }
        System.out.println(System.currentTimeMillis() - start);
    }
}

এই ফলাফলগুলির সাথে:

35 // no reflection
465 // using reflection

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

এমনকি আপনি কেবল তাত্ক্ষণিকভাবে চালিয়ে গেলেও, আপনি এখনও একটি পারফরম্যান্স হিট পাবেন:

30 // no reflection
47 // reflection using one lookup, only instantiating

আবার, ওয়াইএমএমভি।


5
আমার মেশিনে .newInstance () শুধুমাত্র একটি Class.forName () কল স্কোর 30 বা তার বেশি কল। ভিএম সংস্করণের উপর নির্ভর করে, উপযুক্ত ক্যাচিং কৌশলটির সাথে পার্থক্যটি আপনি যতটা ভাবছেন তার চেয়ে বেশি কাছাকাছি হতে পারে।
শন রিলি

56
নীচে পিটার ল্যারি উল্লেখ করেছেন যে এই পরীক্ষাটি সম্পূর্ণরূপে অবৈধ ছিল কারণ সংকলকটি অ-প্রতিবিম্বিত সমাধানটিকে অপ্টিমাইজ করছিল (এটি এমনকি প্রমাণিত করতে পারে যে কিছুই করা হয়নি এবং লুপটি অপ্টিমাইজ করে)। পুনরায় কাজ করা দরকার এবং খারাপ / বিভ্রান্তিকর তথ্য হিসাবে সম্ভবত এসও থেকে অপসারণ করা উচিত। অপ্টিমাইজারটিকে অপ্টিমাইজ করা থেকে বিরত রাখতে উভয় ক্ষেত্রেই তৈরি বস্তুগুলিকে অ্যারেতে ক্যাশে করুন। (এটি প্রতিফলিত পরিস্থিতিতে এটি করতে পারে না কারণ এটি প্রমাণ করতে পারে না যে কনস্ট্রাক্টরের কোনও পার্শ্ব-প্রতিক্রিয়া নেই)
বিল কে

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

4
এটি সম্ভবত একটি অকেজো মানদণ্ড। কি করে কিছু উপর নির্ভর করে on যদি এটি দৃশ্যমান পার্শ্ব প্রতিক্রিয়া সহ কিছুই না করে, তবে আপনার বেঞ্চমার্কটি কেবল ডেড কোড চালায়।
nes1983

9
আমি সবেমাত্র JVM অপ্টিমাইজ প্রতিফলন 35 ভাঁজ প্রত্যক্ষ করেছি। একটি লুপে বারবার পরীক্ষা চালানো আপনি কীভাবে অনুকূলিত কোডটি পরীক্ষা করেন। প্রথম পুনরাবৃত্তি: 3045ms, দ্বিতীয় পুনরাবৃত্তি: 2941ms, তৃতীয় পুনরাবৃত্তি: 90 মিমি, চতুর্থ পুনরাবৃত্তি: 83ms ms কোড: c.newInstance (i)। গ একজন কনস্ট্রাক্টর। প্রতিচ্ছবিবিহীন কোড: নতুন এ (আই), যা 13, 4, 3 .. এমএস সময় দেয়। সুতরাং হ্যাঁ, এই ক্ষেত্রে প্রতিফলনটি ধীর ছিল, তবে লোকেরা যা বলেছে তার তুলনায় প্রায় ধীর নয়, কারণ প্রতিটি পরীক্ষা আমি দেখছি, তারা জেভিএমকে মেশিনের সাথে বাইট কোডগুলি প্রতিস্থাপনের সুযোগ না দিয়ে একবার পরীক্ষা চালাচ্ছে simply কোড।
মাইক

87

হ্যাঁ, এটি ধীর।

তবে জঘন্য # 1 নিয়মটি মনে রাখবেন - প্রাক্কলন অপ্টিমাইজেশন হ'ল সমস্ত মন্দির মূল

(ভাল, ডিআরওয়াইয়ের জন্য # 1 দিয়ে বাঁধা হতে পারে)

আমি শপথ করছি, যদি কেউ আমার কাছে কাজ করে এসে আমাকে জিজ্ঞাসা করে থাকে তবে আমি তাদের কয়েক মাস পরের মাসগুলিতে খুব সচেতন থাকব।

আপনার এটির প্রয়োজন হওয়া নিশ্চিত হওয়া অবধি আপনার কখনই অনুকূলকরণ করা উচিত নয়, ততক্ষণ কেবল ভাল, পঠনযোগ্য কোডটি লিখুন।

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

আমি যখন এই জাতীয় প্রশ্ন শুনতে পেলাম তবে তা ভুলে গিয়েছিলাম তবে আমি ভুলে গেছি যে সত্যই তা পাওয়ার আগে প্রত্যেককেই সমস্ত বিধি নিজেই শিখতে হবে। আপনি "অপটিমাইজড" কাউকে কিছুবার ডিবেগ করার জন্য মাসব্যাপী ব্যয় করার পরে আপনি এটি পাবেন।

সম্পাদনা করুন:

একটি আকর্ষণীয় জিনিস এই থ্রেডে ঘটেছে। # 1 উত্তর যাচাই করুন, কম্পাইলার জিনিসগুলির অনুকূলকরণে কতটা শক্তিশালী তা উদাহরণ example পরীক্ষাটি সম্পূর্ণরূপে অবৈধ কারণ অ-প্রতিবিম্বিত ইনস্ট্যান্টেশন সম্পূর্ণ ফ্যাক্টর আউট করা যায়।

পাঠ? আপনি একটি পরিষ্কার, ঝরঝরে কোডেড সমাধান না লিখে এবং এটি খুব ধীর হিসাবে প্রমাণিত না হওয়া পর্যন্ত কখনই অনুকূলিত হন না।


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

26
-১: ভুল উপায়ে জিনিসগুলি এড়িয়ে চলা অপ্টিমাইজেশন নয়, এটি কেবল জিনিসগুলি করা। বাস্তব বা কল্পিত পারফরম্যান্স উদ্বেগের কারণে অনুকূলকরণটি ভুল, জটিল উপায়ে কাজ করছে।
soru

5
@ সুরু সম্পূর্ণরূপে একমত একটি সন্নিবেশ সাজানোর জন্য একটি অ্যারের তালিকার উপরে একটি লিঙ্কযুক্ত তালিকা নির্বাচন করা সহজ জিনিসগুলি করার সঠিক উপায়। তবে এই বিশেষ প্রশ্নটি - মূল প্রশ্নের উভয় পক্ষেই ভাল ব্যবহারের কেস রয়েছে, সুতরাং সর্বাধিক ব্যবহারযোগ্য সমাধানের চেয়ে পারফরম্যান্সের ভিত্তিতে একটি নির্বাচন করা ভুল হবে। আমি নিশ্চিত নই যে আমরা মোটেও দ্বিমত পোষণ করছি, সুতরাং আপনি কেন "-1" বলেছিলেন তা নিশ্চিত নই।
বিল কে

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

2
@ রিচার্ড রাইলি সাধারণভাবে শ্রেণীর ইনস্ট্যান্টেশন একটি নির্বাচিত শ্রেণীর জন্য বিরল ঘটনা যা আপনি প্রতিফলন ব্যবহার করবেন। আমি মনে করি আপনি ঠিক বলেছেন - কিছু লোক প্রতি ক্লাসে প্রতিবিম্বিত হতে পারে, এমনকি অবিচ্ছিন্নভাবে পুনরায় তৈরি করা হতে পারে। আমি এটি বেশ খারাপ প্রোগ্রামিং বলব (যদিও তারপরেও আপনি সত্যের পরে পুনরায় ব্যবহারের জন্য ক্লাসের উদাহরণগুলির একটি ক্যাশে প্রয়োগ করতে এবং আপনার কোডকে খুব বেশি ক্ষতি না করতে পারেন - তাই আমি অনুমান করি যে আমি এখনও পঠনযোগ্যতার জন্য সবসময় ডিজাইন বলব, তারপরে প্রোফাইল এবং অপ্টিমাইজ করব পরে)
বিল কে

36

আপনি দেখতে পাবেন যে এভি = নতুন এ () জেভিএম দ্বারা অপ্টিমাইজ করা হচ্ছে। আপনি যদি বস্তুকে একটি অ্যারেতে রাখেন তবে তারা এত ভাল সম্পাদন করে না। ;) নিম্নলিখিত প্রিন্টগুলি ...

new A(), 141 ns
A.class.newInstance(), 266 ns
new A(), 103 ns
A.class.newInstance(), 261 ns

public class Run {
    private static final int RUNS = 3000000;

    public static class A {
    }

    public static void main(String[] args) throws Exception {
        doRegular();
        doReflection();
        doRegular();
        doReflection();
    }

    public static void doRegular() throws Exception {
        A[] as = new A[RUNS];
        long start = System.nanoTime();
        for (int i = 0; i < RUNS; i++) {
            as[i] = new A();
        }
        System.out.printf("new A(), %,d ns%n", (System.nanoTime() - start)/RUNS);
    }

    public static void doReflection() throws Exception {
        A[] as = new A[RUNS];
        long start = System.nanoTime();
        for (int i = 0; i < RUNS; i++) {
            as[i] = A.class.newInstance();
        }
        System.out.printf("A.class.newInstance(), %,d ns%n", (System.nanoTime() - start)/RUNS);
    }
}

এটি আমার মেশিনে পার্থক্যটি প্রায় 150 এনএস এর পরামর্শ দেয়।


সুতরাং আপনি সবেমাত্র অপটিমাইজারকে হত্যা করেছেন, সুতরাং এখন উভয় সংস্করণ ধীর। প্রতিফলন তাই অত্যাধিক ধীর।
gbjbaanb

13
@gbjbaanb যদি অপ্টিমাইজার নিজেই সৃষ্টিটিকে অপ্টিমাইজ করে থাকে তবে এটি একটি বৈধ পরীক্ষা ছিল না। @ পিটারের পরীক্ষা তাই বৈধ কারণ এটি প্রকৃতপক্ষে সৃষ্টির সময়ের তুলনা করে (অপ্টিমাইজারটি কোনও বাস্তব-বিশ্বের পরিস্থিতিতে কাজ করতে সক্ষম হবে না কারণ যে কোনও বাস্তব-বিশ্বের পরিস্থিতিতে আপনার যে জিনিসগুলি ইনস্ট্যান্ট করছে তা প্রয়োজন)।
বিল কে

10
@ nes1983 এক্ষেত্রে আপনি আরও ভাল একটি বেঞ্চমার্ক তৈরির সুযোগ নিতে পারেন। সম্ভবত আপনি গঠনমূলক কিছু দিতে পারেন, যেমন পদ্ধতির শরীরে কী হওয়া উচিত।
পিটার লরি 26'12

1
আমার ম্যাক, ওপেনজেডকে 7u4 এ, পার্থক্যটি 95ns বনাম 100ns। অ্যারে এ এর ​​সংরক্ষণ করার পরিবর্তে, আমি হ্যাশকোডগুলি সঞ্চয় করি। যদি আপনি বলছেন -ভারবোজ: শ্রেণি আপনি দেখতে পারবেন কখন হটস্পট এ এবং তার সাথে গতির জন্য নির্মাণের জন্য বাইকোড তৈরি করে।
রন

@ পিটারলাউরে যদি আমি একবার তাকান (এক কল Class.getDeclaredMethod) এবং তারপরে Method.invokeএকাধিকবার কল করি ? আমি একবারে প্রতিবার প্রতিফলনটি ব্যবহার করছি বা যতবার ডাকে? প্রশ্ন অনুসরণ করুন, যদি Methodএটির পরিবর্তে একটি হয় Constructorএবং আমি Constructor.newInstanceএকাধিকবার করি ?
tmj

28

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

কোড জেনারেশন ব্যবহার করে এমন অ্যাপ্লিকেশনগুলির কয়েকটি উদাহরণ:

  • সিজিএলআইবি দ্বারা উত্পাদিত প্রক্সিগুলিতে জাভির গতিশীল প্রক্সিগুলির তুলনায় কিছুটা দ্রুত গতিময় , কারণ সিজিআইএলআইবি তার প্রক্সিগুলির জন্য বাইকোড উত্পন্ন করে, তবে গতিশীল প্রক্সিগুলি কেবল প্রতিচ্ছবি ব্যবহার করে ( আমি সিজিএলআইবি মাপা পদ্ধতি কলগুলিতে প্রায় 10x দ্রুত হতে পেরেছি, তবে প্রক্সিগুলি তৈরি করা ধীর ছিল)।

  • জেরিয়াল প্রতিবিম্ব ব্যবহারের পরিবর্তে সিরিয়ালযুক্ত বস্তুর ক্ষেত্রগুলি পড়ার / লেখার জন্য বাইকোড উত্পন্ন করে। আছে কিছু benchmarks JSerial এর সাইটে।

  • আমি ১০০% নিশ্চিত নই (এবং এখন উত্সটি পড়ার মতো আমার মনে হয় না ) তবে আমি মনে করি গুইস নির্ভরতা ইনজেকশন দেওয়ার জন্য বাইকোড তৈরি করে। আমি ভুল হলে শুধরে.


27

"উল্লেখযোগ্য" সম্পূর্ণ প্রসঙ্গে নির্ভরশীল।

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

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


24

প্রতিবিম্ব সহ কিছু ওভারহেড রয়েছে তবে এটি আধুনিক ভিএমগুলিতে আগের তুলনায় অনেক ছোট।

আপনি যদি আপনার প্রোগ্রামে প্রতিটি সাধারণ বস্তু তৈরি করতে প্রতিবিম্ব ব্যবহার করে থাকেন তবে কিছু ভুল। মাঝে মাঝে এটি ব্যবহার করা যখন আপনার ভাল কারণ থাকে তখন মোটেও সমস্যা হওয়া উচিত নয়।


11

হ্যাঁ প্রতিবিম্বটি ব্যবহার করার সময় একটি পারফরম্যান্স হিট হয় তবে অনুকূলকরণের জন্য একটি সম্ভাব্য কাজের পদ্ধতিটি ক্যাশে করছে:

  Method md = null;     // Call while looking up the method at each iteration.
      millis = System.currentTimeMillis( );
      for (idx = 0; idx < CALL_AMOUNT; idx++) {
        md = ri.getClass( ).getMethod("getValue", null);
        md.invoke(ri, null);
      }

      System.out.println("Calling method " + CALL_AMOUNT+ " times reflexively with lookup took " + (System.currentTimeMillis( ) - millis) + " millis");



      // Call using a cache of the method.

      md = ri.getClass( ).getMethod("getValue", null);
      millis = System.currentTimeMillis( );
      for (idx = 0; idx < CALL_AMOUNT; idx++) {
        md.invoke(ri, null);
      }
      System.out.println("Calling method " + CALL_AMOUNT + " times reflexively with cache took " + (System.currentTimeMillis( ) - millis) + " millis");

ফলাফল হবে:

[জাভা] কল করার পদ্ধতিটি 1000000 বার রিফ্লেক্সিভলি সাথে লুকোচুরির সাথে লেগেছিল 5618 মিলিস

[জাভা] ক্যাচ দিয়ে কলিং পদ্ধতিটি 1000000 বার রিফ্ল্যাক্সিভালি 270 মিলিস নিয়েছিল


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

7

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

সচেতন থাকুন যে এই থ্রেডের মাইক্রোব্যাঙ্কমার্কগুলি গভীরভাবে ত্রুটিযুক্ত রয়েছে, তাই তাদের সাথে লবণের দানা নিয়ে নিন। পিটার লরির সর্বদাই ত্রুটিযুক্ত: পদ্ধতিগুলি জিট করার জন্য এটি ওয়ার্মআপ চালায় এবং বরাদ্দ আসলেই ঘটছে কিনা তা নিশ্চিত করার জন্য এটি (সচেতনভাবে) পলায়ন বিশ্লেষণকে পরাস্ত করে। এমনকি এটির একটিরও সমস্যা রয়েছে যদিও: উদাহরণস্বরূপ, অ্যারে স্টোরের বিশাল সংখ্যক ক্যাশে এবং স্টোর বাফারকে পরাস্ত করতে পারে বলে আশা করা যায়, তাই আপনার বরাদ্দ খুব দ্রুত হলে এটি বেশিরভাগই একটি স্মৃতি মাপকাঠি হয়ে যায়। (এই উপসংহারটি সঠিকভাবে পাওয়ার পরে কুডোস যদিও: পার্থক্যটি "2.5x" না বলে "150ns" is আমার সন্দেহ হয় যে তিনি জীবিতদের জন্য এই জাতীয় কাজ করেন।)


7

আকর্ষণীয়ভাবে যথেষ্ট, সেটএ্যাক্সেসেবল (সত্য) স্থির করে, যা সুরক্ষা চেক এড়িয়ে চলেছে, তাতে ব্যয় 20% হ্রাস পেয়েছে।

সেট অ্যাক্সেসেবল (সত্য) ব্যতীত

new A(), 70 ns
A.class.newInstance(), 214 ns
new A(), 84 ns
A.class.newInstance(), 229 ns

সেট অ্যাক্সেসেবল (সত্য) সহ

new A(), 69 ns
A.class.newInstance(), 159 ns
new A(), 85 ns
A.class.newInstance(), 171 ns

1
নীতিগতভাবে আমার কাছে সুস্পষ্ট বলে মনে হচ্ছে। অনুরোধগুলি চলাকালীন এই সংখ্যাগুলি কি রৈখিকভাবে স্কেল করে 1000000?
লুকাশ এদার

প্রকৃতপক্ষে setAccessible()একাধিক যুক্তিযুক্ত পদ্ধতিগুলির ক্ষেত্রে সাধারণভাবে আরও অনেক বেশি পার্থক্য থাকতে পারে, তাই এটি সর্বদা বলা উচিত।
স্টেক্সম্যান

6

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


1
+1 আমারও অনুরূপ অভিজ্ঞতা হয়েছে। প্রতিবিম্বটি একেবারে প্রয়োজনীয় হলে এটি ব্যবহার করা নিশ্চিত করা ভাল।
রায়ান টেমস

যেমন এওপি ভিত্তিক লাইব্রেরিগুলির প্রতিচ্ছবি প্রয়োজন।
গৌরব

4

ক্লাসে ডাকা নতুন সংস্করণ () পরিবর্তে ক্লাস.ফোর্নাম ("মিসক্যা.এ") এর জন্য (যার জন্য একটি ক্লাস লুকের প্রয়োজন হবে, ফিলিস্টেমের উপর সম্ভবত ক্লাস পাথটি স্ক্যান করা প্রয়োজন) ডোরআরফ্ল্যাশনে () ওভারহেড। আমি ভাবছি যে পরিসংখ্যানগুলি দেখতে কেমন হবে যদি Class.forName ("Misc.A") কেবলমাত্র একবার লুপের বাইরে করা হয়, এটি লুপের প্রতিটি অনুরোধের জন্য করা উচিত নয়।


1

হ্যাঁ, সর্বদা প্রতিবিম্ব দ্বারা একটি অবজেক্ট তৈরি করা ধীর হবে কারণ জেভিএম সংকলনের সময় কোডটি অনুকূলিত করতে পারে না। আরও বিশদের জন্য সান / জাভা প্রতিবিম্ব টিউটোরিয়াল দেখুন See

এই সাধারণ পরীক্ষাটি দেখুন:

public class TestSpeed {
    public static void main(String[] args) {
        long startTime = System.nanoTime();
        Object instance = new TestSpeed();
        long endTime = System.nanoTime();
        System.out.println(endTime - startTime + "ns");

        startTime = System.nanoTime();
        try {
            Object reflectionInstance = Class.forName("TestSpeed").newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        endTime = System.nanoTime();
        System.out.println(endTime - startTime + "ns");
    }
}

3
মনে রাখবেন যে আপনার Class.forName()চেহারা () ইনস্ট্যান্সেশন (newInstance ()) থেকে পৃথক করা উচিত , কারণ এগুলি তাদের কর্মক্ষমতা বৈশিষ্ট্যের ক্ষেত্রে উল্লেখযোগ্যভাবে পরিবর্তিত হয় এবং আপনি মাঝে মাঝে একটি সুনির্দিষ্টভাবে নকশিত সিস্টেমে পুনরাবৃত্তিটি এড়াতে পারেন।
জোছিম সউর

3
এছাড়াও: আপনাকে একটি কার্যকর বেঞ্চমার্ক পাওয়ার জন্য প্রতিটি টাস্কটি অনেকবারই সম্পাদন করতে হবে: প্রথমত কার্যকরভাবে নির্ভরযোগ্যতার সাথে পরিমাপ করা সম্ভব নয় এবং দ্বিতীয়ত দরকারী নম্বর পেতে আপনাকে হটস্পট ভিএম গরম করতে হবে।
জোছিম সউর

1

প্রায়শই আপনি অ্যাপাচি কমন্স বিয়ান ইউটিস বা প্রপার্টি ইউটিগুলি ব্যবহার করতে পারেন যা অন্তঃনির্ধারণ (মূলত তারা ক্লাসগুলি সম্পর্কে মেটা ডেটা ক্যাশে করে যাতে তাদের সর্বদা প্রতিচ্ছবি ব্যবহার করার প্রয়োজন হয় না)।


0

আমি মনে করি এটি টার্গেট পদ্ধতিটি কত হালকা / ভারী on যদি লক্ষ্য পদ্ধতিটি খুব হালকা হয় (উদাহরণস্বরূপ গিটার / সেটার), এটি 1 ~ 3 গুণ ধীর হতে পারে। যদি লক্ষ্য পদ্ধতিটি প্রায় 1 মিলিসেকেন্ড বা তারও বেশি সময় নেয় তবে পারফরম্যান্সটি খুব কাছাকাছি থাকবে। আমি জাভা 8 এবং প্রতিচ্ছবি দিয়ে যা পরীক্ষা করেছি তা এখানে :

public class ReflectionTest extends TestCase {    
    @Test
    public void test_perf() {
        Profiler.run(3, 100000, 3, "m_01 by refelct", () -> Reflection.on(X.class)._new().invoke("m_01")).printResult();    
        Profiler.run(3, 100000, 3, "m_01 direct call", () -> new X().m_01()).printResult();    
        Profiler.run(3, 100000, 3, "m_02 by refelct", () -> Reflection.on(X.class)._new().invoke("m_02")).printResult();    
        Profiler.run(3, 100000, 3, "m_02 direct call", () -> new X().m_02()).printResult();    
        Profiler.run(3, 100000, 3, "m_11 by refelct", () -> Reflection.on(X.class)._new().invoke("m_11")).printResult();    
        Profiler.run(3, 100000, 3, "m_11 direct call", () -> X.m_11()).printResult();    
        Profiler.run(3, 100000, 3, "m_12 by refelct", () -> Reflection.on(X.class)._new().invoke("m_12")).printResult();    
        Profiler.run(3, 100000, 3, "m_12 direct call", () -> X.m_12()).printResult();
    }

    public static class X {
        public long m_01() {
            return m_11();
        }    
        public long m_02() {
            return m_12();
        }    
        public static long m_11() {
            long sum = IntStream.range(0, 10).sum();
            assertEquals(45, sum);
            return sum;
        }    
        public static long m_12() {
            long sum = IntStream.range(0, 10000).sum();
            assertEquals(49995000, sum);
            return sum;
        }
    }
}

সম্পূর্ণ পরীক্ষার কোডটি গিটহাব: রিফ্লেকশন টেস্ট.জভাতে উপলব্ধ

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