प्रौद्योगिकी साझेदारी

एण्ड्रॉयड् प्रदर्शन अनुकूलन स्मृति अनुकूलनम्

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

एण्ड्रॉयड् प्रदर्शन अनुकूलन स्मृति अनुकूलनम्

स्मृतिसमस्या

  • स्मृति मर्दनम्
  • स्मृति लीक
  • स्मृति-अतिप्रवाहः

स्मृति मर्दनम्

स्मृति-प्रहारः अल्पकाले एव बहूनां वस्तूनाम् निर्माणं विनाशं च निर्दिशति, यस्य परिणामेण बहुधा कचरा-संग्रहणं (Garbage Collection, GC) क्रियाकलापाः भवन्ति एषा नित्यं GC क्रियाकलापः बहु CPU संसाधनं गृह्णाति तथा च अनुप्रयोगविलम्बः अथवा कार्यक्षमतायाः अवनतिं जनयितुं शक्नोति ।

कार्यप्रदर्शनम् : स्मृतिवक्रं दन्तयुक्तं भवति ।

स्मृति लीक

स्मृति-लीकः तदा भवति यदा कश्चन अनुप्रयोगः तेषां वस्तूनाम् सन्दर्भान् धारयति येषां आवश्यकता नास्ति, येन एतानि वस्तूनि कचरा-संग्राहकेन पुनः न प्रयुज्यन्ते, अतः स्मृतिस्थानं गृह्णाति यत् मुक्तं भवितुम् अर्हति स्म कालान्तरे स्मृतिलीकस्य परिणामः न्यूनाधिकं न्यूनतया उपलब्धं स्मृतिः भवति, यत् अन्ते अनुप्रयोगस्य दुर्घटना अथवा कार्यक्षमतायाः अवनतिं जनयितुं शक्नोति ।

स्मृति-अतिप्रवाहः

स्मृति-अतिप्रवाहः तदा भवति यदा कश्चन अनुप्रयोगः अधिकं स्मृतिस्थानं आवंटयितुं प्रयतते, परन्तु प्रणाली अनुरोधं पूरयितुं असमर्था भवति यतोहि आवंटनार्थं पर्याप्तं स्मृतिस्थानं नास्ति एतेन प्रायः अनुप्रयोगः OutOfMemoryError अपवादं क्षिपति ।

अन्वेषणसाधनम्

  • स्मृति प्रोफाइलर
  • स्मृति विश्लेषक
  • लीककैनरी

स्मृति प्रोफाइलर

  • Memory Profiler इति स्मृतिविश्लेषणसाधनं यत् Android Studio इत्यनेन सह आगच्छति ।
  • कार्यक्रमस्मृतेः उपयोगं दर्शयति वास्तविकसमयस्य आलेखः ।
  • स्मृति-लीक्स्, थ्रेशिंग्, इत्यादीनि चिन्वन्तु ।
  • ढेर डम्प्स् गृहीतुं, GC बलं कर्तुं, स्मृतिविनियोगं च अनुसरणं कर्तुं क्षमताम् प्रदाति ।

स्मृति विश्लेषक

  • स्मृति-लीक्स् तथा स्मृति-उपयोगं अन्वेष्टुं शक्तिशाली Java Heap विश्लेषण-उपकरणम् ।
  • समग्रप्रतिवेदनानि जनयन्तु, मुद्देषु विश्लेषणं कुर्वन्तु, इत्यादीनि च।

लीककैनरी

  • स्वचालित स्मृति लीक पता लगाना।
    • LeakCanary स्वयमेव एतेषु वस्तुषु लीकं पश्यति: Activity, Fragment, View, ViewModel, Service.
  • आधिकारिकजालस्थलम् : https://github.com/square/leakcanary

स्मृति प्रबन्धन तन्त्र

जावा

जावा स्मृतिसंरचना: ढेरः, आभासीयन्त्रस्य ढेरः, विधिक्षेत्रः, कार्यक्रमगणकः, स्थानीयविधिढेरः ।

जावा स्मृतिपुनःप्रयोगस्य एल्गोरिदम् : १.

  • मार्क-एण्ड-स्वीप एल्गोरिदम् : १.
    1. पुनःप्रयोगः करणीयः वस्तुनि चिह्नितव्यम्
    2. सर्वाणि चिह्नितानि वस्तूनि एकरूपेण पुनः प्रयोजयन्तु।
  • प्रतिलिपि एल्गोरिदम् : १.
    1. स्मृतिं समानप्रमाणस्य द्वयोः खण्डयोः विभजन्तु ।
    2. एकस्य स्मृतिखण्डस्य उपयोगानन्तरं जीवितानि वस्तूनि अन्यस्मिन् खण्डे प्रतिलिप्यन्ते ।
  • चिह्न-संयोजन-अल्गोरिदम् : १.
    1. चिह्नप्रक्रिया "mark-and-sweep" इति अल्गोरिदम् इत्यस्य समाना अस्ति ।
    2. जीवितवस्तूनि एकं अन्तं गच्छन्ति।
    3. अवशिष्टं स्मृतिं स्वच्छं कुर्वन्तु।
  • पीढी संग्रह एल्गोरिदम : १.
    • बहुसंग्रह-अल्गोरिदम्-इत्यस्य लाभं संयोजयन्तु ।
    • नवीनपीढीवस्तूनाम् जीवितस्य दरः न्यूनः भवति तथा च प्रतिलिपि एल्गोरिदम् उपयुज्यते ।
    • पुरातनपीढीयां वस्तुनां जीवितस्य दरः अधिकः भवति तथा च चिह्न-क्रमण-अल्गोरिदम् उपयुज्यते ।

मार्क-क्लियर एल्गोरिदमस्य दोषाः : चिह्नीकरणं क्लियरिंग् च कुशलं न भवति तथा च बहूनां असंततस्मृतिखण्डानां उत्पादनं करिष्यति ।

प्रतिकृति एल्गोरिदम् : कार्यान्वयनार्थं सरलं चालयितुं च कुशलम्। हानिः - अन्तरिक्षस्य अर्धं अपव्ययितम्।

मार्क-कम्पैक्ट एल्गोरिदम् : मार्क-क्लीन इत्यस्य कारणेन स्मृतिविखण्डनं परिहरन्तु तथा च प्रतिलिपि एल्गोरिदम् इत्यस्य स्थानं अपव्ययितुं परिहरन्तु ।

एण्ड्रॉयड्

एण्ड्रॉयड् मेमोरी लोचदारविनियोगः, आवंटनमूल्यं, अधिकतममूल्यं च विशिष्टयन्त्रैः प्रभावितं भवति ।

डालविक् रीसाइक्लिंग एल्गोरिदम् तथा एआरटी रीसाइक्लिंग एल्गोरिदम् इत्येतौ द्वौ अपि एण्ड्रॉयड् ऑपरेटिंग् सिस्टम् इत्यस्मिन् स्मृतिप्रबन्धनार्थं प्रयुक्तौ कचरासंग्रहणतन्त्रौ स्तः ।

डालविक पुनर्चक्रण एल्गोरिदम् : १.

  • मार्क-एण्ड-स्वीप एल्गोरिदम।
  • लाभः अस्ति यत् तस्य कार्यान्वयनम् सरलम् अस्ति । दोषः अस्ति यत् चिह्नीकरण-समाशोधन-चरणयोः समये अनुप्रयोगस्य निष्पादनं विरामं प्राप्स्यति, येन अनुप्रयोगः अस्थायीरूपेण जमति, उपयोक्तृ-अनुभवं च प्रभावितं करिष्यति

कला पुनःप्रयोग एल्गोरिदम् : १.

  • कचरा संग्रहण संकुचितस्य एल्गोरिदम। कचरासंग्रहणस्य समये विरामसमयं न्यूनीकर्तुं मार्क-स्वीप् एल्गोरिदम् इत्यस्य आधारेण सुधारः कृतः अस्ति ।
  • समवर्ती चिह्नीकरणम् : एआरटी समवर्ती चिह्नीकरणचरणस्य परिचयं करोति, यस्य अर्थः अस्ति यत् एतत् अनुप्रयोगस्य निष्पादनेन सह समवर्तीरूपेण भवितुम् अर्हति । एतेन कचरासंग्रहणस्य कारणेन विरामसमयः न्यूनीकरोति ।
  • सफाई तथा संपीडनम् : सफाई चरणे एआरटी न केवलं अचिह्नितवस्तूनि स्वच्छं करोति, अपितु स्मृतिम् अपि संकुचितं करोति, यस्य अर्थः अस्ति यत् स्मृतिविखण्डनं न्यूनीकर्तुं जीवितवस्तूनि एकत्र चालयति एतेन स्मृतिप्रबन्धनं अधिकं कार्यक्षमं भवति तथा च स्मृतिविनियोगविफलतायाः सम्भावना न्यूनीभवति ।
  • अनुकूली संग्रहणम् : एआरटी अनुकूलसङ्ग्रहस्य अवधारणाम् अपि प्रवर्तयति, यस्य अर्थः अस्ति यत् एतत् स्वयमेव अनुप्रयोगस्य व्यवहारस्य स्मृतिप्रयोगस्य च प्रतिमानस्य आधारेण कचरासंग्रहणस्य आवृत्तिं, प्रकारं च समायोजयति एतेन एआरटी भिन्न-भिन्न-अनुप्रयोग-आवश्यकतानां अनुकूलतया अधिकतया अनुकूलतां प्राप्नोति ।

एलएमके तन्त्रम् : १.

  • Low Memory Killer तन्त्रम्।
  • अस्य मुख्यं कार्यं भवति यदा प्रणालीस्मृतिः स्मृतिं मुक्तुं अपर्याप्तं भवति तथा च प्रणालीस्थिरतां प्रतिक्रियाशीलतां च सुनिश्चितं करोति तदा निश्चितप्राथमिकतानीत्यानुसारं केषाञ्चन पृष्ठभूमिप्रक्रियाणां समाप्तिः भवति

उत्तरयति

स्मृति थ्रेशिंग समस्या

अनुकरण समस्या कोड
public class ShakeActivity extends AppCompatActivity {

    private static Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            String str = "";
            for (int i = 0; i < 10000000; i++) {
                str += i;
            }
            mHandler.sendEmptyMessageDelayed(1, 30);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shake);
    }

    public void startClick(View view) {
        mHandler.sendEmptyMessage(1);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
ज्ञातुं Memory Profiler tool इत्यस्य उपयोगं कुर्वन्तु

मेमोरी प्रोफाइलर स्मृतिविनियोगान् द्रष्टुं शक्नोति, "Record Java/Kotlin allocations" इत्यत्र क्लिक् कुर्वन्तु ।

अत्र चित्रविवरणं सम्मिलितं कुर्वन्तु

उपर्युक्तस्य अर्थः : १.

  • जावा : जावा अथवा कोट्लिन् कोडद्वारा आवंटिता स्मृतिः ।
  • मूलनिवासी : C अथवा C++ कोडेन आवंटिता स्मृतिः ।
  • ग्राफिक्स् : ग्राफिक्स् बफर कतारेण स्क्रीन् प्रति पिक्सेल्स् (GL पृष्ठानि, GL ​​टेक्सचर इत्यादीनि च समाविष्टानि) प्रदर्शयितुं प्रयुक्ता स्मृतिः । CPU साझा स्मृति।
  • Stack: अनुप्रयोगे native stack तथा Java stack इत्यनेन प्रयुक्ता स्मृतिः । प्रायः एतस्य सम्बन्धः अस्ति यत् भवतः एप् कियन्तः थ्रेड् चालयति इति ।
  • अनुप्रयोगैः कोडं संसाधनं च संसाधितुं प्रयुक्ता स्मृतिः यथा dex bytecode, अनुकूलितः अथवा संकलितः dex code, .so पुस्तकालयाः, फन्ट् च ।
  • अनुप्रयोगः स्मृतिं उपयुङ्क्ते यस्याः वर्गीकरणं कथं कर्तव्यमिति प्रणाली अनिश्चिता अस्ति ।
  • अनुप्रयोगेन आवंटितानां जावा/कोट्लिन् वस्तुनां संख्या । एषा संख्या C अथवा C++ इत्यत्र आवंटितानां वस्तूनाम् अवलोकनं न करोति ।

निम्नलिखितार्थाः- १.

  • आवंटनम् : उत्तीर्णता malloc() वाnew संचालकेन आवंटितानां वस्तूनाम् संख्या ।
  • विनियोजनम् : मार्गेण free() वाdelete संचालकेन विनियोगितानां वस्तूनाम् संख्या ।
  • Allocations Size: चयनितसमयावधिमध्ये सर्वेषां आवंटनानां कुलआकारः, बाइट्-मात्रायां ।
  • Deallocations Size: चयनितसमयावधिमध्ये मुक्तस्य स्मृतेः कुलआकारः, बाइट्-मात्रायां ।
  • कुलगणना : आवंटनानि विनियोगानि न्यूनीकृतानि।
  • शेषः आकारः : आवंटनानां आकारः विनियोजनानां आकारः न्यूनीकृतः ।
  • Shallow Size: राशेः सर्वेषां दृष्टान्तानां कुल आकारः, बाइट्-मात्रायां ।

उपर्युक्तचित्रस्य विश्लेषणम् : १.

अत्र चित्रविवरणं सम्मिलितं कुर्वन्तु

अस्मिन् क्षेत्रे Allocations तथा Deallocations इत्येतयोः मूल्यानि तुल्यकालिकरूपेण समानानि सन्ति, तथा च Shallow Size तुल्यकालिकरूपेण विशालः अस्ति, यत् सूचयति यत् वस्तुनि बहुधा निर्मिताः नष्टाः च भवितुम् अर्हन्ति

अत्र चित्रविवरणं सम्मिलितं कुर्वन्तु

क्लिक् कृत्वा, भवान् call stack सूचनां द्रष्टुं शक्नोति, तथा च code इत्यनेन सह मिलित्वा, Handler मध्ये memory jitter समस्या अस्ति इति अनुमानं कर्तुं शक्नोति ।

अनुकूलनयुक्तयः
  • बहुधा वस्तुनिर्माणं नाशं च परिहरन्तु।

स्मृति लीक समस्या

अनुकरण समस्या कोड
public class CallbackManager {
    public static ArrayList<Callback> sCallbacks = new ArrayList<>();

    public static void addCallback(Callback callback) {
        sCallbacks.add(callback);
    }

    public static void removeCallback(Callback callback) {
        sCallbacks.remove(callback);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
public class LeakActivity extends AppCompatActivity implements Callback {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);
        ImageView imageView = findViewById(R.id.imageView);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.splash);
        imageView.setImageBitmap(bitmap);
        CallbackManager.addCallback(this);
    }

    @Override
    public void onOperate() {

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
अन्वेषणार्थं LeakCanary इति साधनस्य उपयोगं कुर्वन्तु

आश्रितपुस्तकालयाः योजयन्तु : १.

debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
  • 1

स्मृतिलीकस्य अनन्तरं LeakCanary प्रासंगिकसूचनाः जनयिष्यति स्वयमेव च डम्पं करिष्यति:

अत्र चित्रविवरणं सम्मिलितं कुर्वन्तु

यथा उपरिष्टात् चित्रात् दृश्यते: LeakActivity इत्यत्र स्मृतिलीकः अस्ति, सन्दर्भशृङ्खलासम्बन्धः च प्रदर्शितः भवति ।

अवश्यं, भवान् hprof सञ्चिकां जनयित्वा Profiler tool इत्यस्य माध्यमेन विशिष्टसूचनाः अपि द्रष्टुं शक्नोति:

अत्र चित्रविवरणं सम्मिलितं कुर्वन्तु

यथा उपरिष्टात् चित्रात् दृश्यते: LeakActivity सहितं 10 लीक-बिन्दवः अभवन्, स्मृति-लीक-वस्तुं द्रष्टुं, सन्दर्भ-शृङ्खलायाः जाँचार्थं च LeakActivity इत्यत्र क्लिक् कुर्वन्तु ।

अनुकूलनयुक्तयः
  • संग्रहतत्त्वानां समये पुनःप्रयोगः।
  • अत्यधिकप्रसङ्गानां स्थिरसन्दर्भान् परिहरन्तु ।
  • स्थिर आन्तरिकवर्गाणां उपयोगं कुर्वन्तु।
  • संसाधनवस्तूनि शीघ्रं पिधायन्तु।

बिटमैप अनुकूलन

यदि भवान् Bitmap इत्यस्य उपयोगानन्तरं चित्रसम्पदां न मुञ्चति तर्हि तस्य कारणं सुलभम्स्मृति लीकं भवति, यस्य परिणामेण स्मृतिः अतिप्रवाहः भवति

बिटमैप स्मृतिप्रतिरूप
  • api10 (Android 2.3.3) इत्यस्मात् पूर्वं: बिटमैप् ऑब्जेक्ट्स् heap memory इत्यत्र स्थापिताः भवन्ति, पिक्सेल डाटा च स्थानीयस्मृतौ स्थापिताः भवन्ति ।
  • api10 इत्यस्य अनन्तरं: सर्वं ढेरस्मृतौ।
  • api26 (Android8.0) इत्यस्य अनन्तरं: पिक्सेल-दत्तांशः स्थानीयस्मृतौ स्थापितः भवति । एतेन देशीयस्तरस्य Bitmap पिक्सेलदत्तांशः जावास्तरस्य वस्तुभिः सह शीघ्रं मुक्तः भवति ।

स्मृतिपुनःप्रयोगः : १.

  • एण्ड्रॉयड् ३.० इत्यस्मात् पूर्वं भवद्भिः तत् मैन्युअल् रूपेण आह्वयितुं आवश्यकम्Bitmap.recycle()Bitmap पुनःप्रयोगं कुर्वन्तु।
  • एण्ड्रॉयड् ३.० तः आरभ्य, प्रणाली अधिकं बुद्धिमान् स्मृतिप्रबन्धनं प्रदाति, अधिकांशेषु सन्दर्भेषु बिटमैप् इत्यस्य पुनःप्रयोगस्य आवश्यकता नास्ति ।

बिटमैप पिक्सेल विन्यासः १.

Configकब्जाकृतः बाइट् आकारः (बाइट्) २.दृष्टान्तरूपेण दर्शयतु
आल्फा_८1एकल पारदर्शी चैनल
आरजीबी_५६५2सरल आरजीबी टिंट
एआरजीबी_८८८८4२४-बिट् सत्या वर्णः
आरजीबीए_एफ168एण्ड्रॉयड् ८.० नवीनम् (HDR) २.

Btimap द्वारा आक्रान्तस्मृतेः गणनां कुर्वन्तु:

  • बिटमैप # getByteCount () 1।
  • getWidth() * getHeight() * १ पिक्सेल स्मृतिं गृह्णाति
संसाधनसञ्चिकानिर्देशिका

संसाधनसञ्चिकासमस्या : १.

  • mdpi (मध्यम घनत्व): लगभग 160dpi, 1x संसाधन।
  • hdpi (उच्चघनत्व): प्रायः २४०dpi, १.५x संसाधनम् ।
  • xhdpi (अतिरिक्त उच्चघनत्व): लगभग 320dpi, 2x संसाधनम्।
  • xxhdpi (अतिरिक्त अल्ट्रा उच्च घनत्व): लगभग 480dpi, 3x संसाधनम्।
  • xxxhdpi (अतिरिक्त अल्ट्रा उच्च घनत्व): लगभग 640dpi, 4x संसाधनम्।

परीक्षणसङ्केतः : १.

private void printBitmap(Bitmap bitmap, String drawable) {
    String builder = drawable +
            " Bitmap占用内存:" +
            bitmap.getByteCount() +
            " width:" +
            bitmap.getWidth() +
            " height:" +
            bitmap.getHeight() +
            " 1像素占用大小:" +
            getByteBy1px(bitmap.getConfig());
    Log.e("TAG", builder);
}

private int getByteBy1px(Bitmap.Config config) {
    if (Bitmap.Config.ALPHA_8.equals(config)) {
        return 1;
    } else if (Bitmap.Config.RGB_565.equals(config)) {
        return 2;
    } else if (Bitmap.Config.ARGB_8888.equals(config)) {
        return 4;
    }
    return 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
// 逻辑密度
float density = metrics.density;
// 物理密度
int densityDpi = metrics.densityDpi;
Log.e("TAG", density + "-" + densityDpi);

// 1倍图
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.splash1);
printBitmap(bitmap1, "drawable-mdpi");

// 2倍图
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.splash2);
printBitmap(bitmap2, "drawable-xhdpi");

// 3倍图
Bitmap bitmap3 = BitmapFactory.decodeResource(getResources(), R.drawable.splash3);
printBitmap(bitmap3, "drawable-xxhdpi");

// 4倍图
Bitmap bitmap4 = BitmapFactory.decodeResource(getResources(), R.drawable.splash4);
printBitmap(bitmap4, "drawable-xxxhdpi");

// drawable
Bitmap bitmap5 = BitmapFactory.decodeResource(getResources(), R.drawable.splash);
printBitmap(bitmap5, "drawable");
/*
        3.0-480
        drawable-mdpi Bitmap占用内存:37127376 width:2574 height:3606 1像素占用大小:4
        drawable-xhdpi Bitmap占用内存:9281844 width:1287 height:1803 1像素占用大小:4
        drawable-xxhdpi Bitmap占用内存:4125264 width:858 height:1202 1像素占用大小:4
        drawable-xxxhdpi Bitmap占用内存:2323552 width:644 height:902 1像素占用大小:4
        drawable Bitmap占用内存:37127376 width:2574 height:3606 1像素占用大小:4
         */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

दृष्टान्तरूपेण दर्शयतु : १.

mdpi उपकरणेषु 1dpxhdpi उपकरणेषु 1px, 1dpxxhdpi उपकरणे 2px, 1dp==3px ।

अतः वर्तमानं यन्त्रं xxhdpi अस्ति, अतः xxhdpi संसाधनस्य अधः समानस्य चित्रस्य विस्तारः ८५८, mdpi संसाधनस्य अन्तर्गतं तस्य ३ गुणाः विस्तारः भविष्यति तथा च विस्तारः २५७४ अस्ति, तथा च xhdpi संसाधनस्य अधः १.५ गुणाः वर्धितः भविष्यति तथा च विस्तारः १२८७ अस्ति ।

अनुकूलनयुक्तयः
  • प्रतिबिम्बसंसाधनानाम् अनेकसमूहाः स्थापयन्तु।
  • समुचितं डिकोडिंग् पद्धतिं चिनुत ।
  • चित्रसञ्चयं स्थापयतु।

स्रोत कोड डाउनलोड