Memory Leak یا کمبود حافظه چیست ؟
سلام دوستان عزیز در این سری از آموزش های برنامه نویسی اندروید به بررسی Memory Leak یا کمبود حافظه می پردازیم در ادامه با همراه باشید.
همانطور که اسمش بروی آن است Memory Leak به معنی کمبود حافظه است و در کل هشت حالت وجود دارد که کمبود حافظه اتفاق می افتد. یکی از فواید garbage-collecting-language (زبان جمع آوری زباله) مانند جاوا که به برای توسعه دهندگان به صراحت مدیتریت حافظه اختصاص داده شده ( allocated memory ) را فراهم می کند. علت این کار احتمالا کاهش خطاها (Crash شدن برنامه ) بوده است. اما حافظه به صورت منطقی می تواند leak شود یعنی احتمال ایجاد کمبود حافظه توسط کدهای منطقی جاوا وجود دارد. در نهایت این به این معنی است که ممکن است اپلیکیشن های اندروید هنوز مستعد پذیرش برای هرز دادن حافظه غیر قابل لازم ( unnecessary memory ) و سبب ایجاد خطای out-of-memory ( خارج از حافظه ) یا oom می شود.خداروشکر هر اکتیویتی همانطور که در پست قبلی مربوط به اکتیویتی به آن اشاره کردیم (سرچ کنید در سایت هست) یک Lifecycle یا چرخه زندگی داره که مهمترینش برای ما onDestroy هست همانطور که توضیح داده بودیم این متد زمانی که چرخه زندگی یک اکتیویتی به پایان می رسد باید اجرا شود.حال به هشت دلیل از Memory Leak می پردازیم
1-Static Activities یا اکتیویتی های ایستا
راحت ترین راه برای memory leak تعریف یک نوع متغیر از نوع static درون همان اکتیوتی است و سپس یک نمونه (instance) از آن را اجرا کنیم ! در زیر یک نمونه از آن را می بینید.
1 2 3 4 5 6 7 8 9 10 | void setStaticActivity() { activity = this; } View saButton = findViewById(R.id.sa_button); saButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setStaticActivity(); nextActivity(); } }); |
الان نوع متغیر static قرار نگرفته است اما چون در اکتویتی است از نوع static در نظر گرفته شده است . و مقدار this (که خود اکتیویتی است) درون متغیر activity قرار گرفته است (مثل این می ماند که شما یک کار را مداوم انجام دهید) زمانی که آن را اجرا کنید با خطای زیر مواجه می شوید.
2-Static Views یا View های ایستا
اگر به طور مکرر و زیاد بخواهیم مقدار id (منظور پیدا کردن id و ریختن آن در یک متغیر البته اینجا از متغیر خود آن استفاده نمی کنیم بلکه از View استفاده کردیم) را درون متغیر از نوع View بریزیم هم سبب ایجاد خطای Memory Leak می شویم همانند مثال زیر
1 2 3 4 5 6 7 8 9 10 | void setStaticView() { view = findViewById(R.id.sv_button); } View svButton = findViewById(R.id.sv_button); svButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setStaticView(); nextActivity(); } }); |
با اجرای کد بالا خطای زیر برای شما نمایان می شود (به طور معمول برنامه force Close می دهد شما بخش Android Monitor را نگاه کنید)
3- Inner Classes یا کلاس داخلی
اگر کلاس داخلی ایجاد کنیم سپس درون آن کلاس داخلی یک مثالی از همان کلاس ایجاد کنیم سبب Memory Leak می شود همانند زیر
1 2 3 4 5 6 7 8 9 10 11 12 | void createInnerClass() { class InnerClass { } inner = new InnerClass(); } View icButton = findViewById(R.id.ic_button); icButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { createInnerClass(); nextActivity(); } }); |
در بالا کلاس ایجاد شده سپس یک نمونه (instance) از همان کلاس در خودش ایجاد شده.
با اجرا به خطای زیر برخورد خواهید کرد
4-Anonymous Classes یا کلاس های ناشناس
اگر ما یک کلاسی درست کنیم که به طور مثال کار AsyncTask در آن وجود داشته و درون این کلاس کاری باشید که هیچ وقت به اتمام نرسد (یک حلقه بی پایان) سبب memory Leak می شود
همانند زیر
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | void startAsyncTask() { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { while(true); } }.execute(); } super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); View aicButton = findViewById(R.id.at_button); aicButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startAsyncTask(); nextActivity(); } }); |
همانطور که میبیند در Async در قسمت doInbakground یک while (حلقه بی پایان) تعریف شده است.
و با خطای زیر در صورت اجرا مواجه می شوید.
5-Handlers یا دستیار ها
همانند قبلی اگر درون PostDelay (یک مقدار زمانی برای تاخیر است) یک حلقه اجرا شود سبب خطای Memory leak می شود.
کد زیر را نگاه کنید
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | void createHandler() { new Handler() { @Override public void handleMessage(Message message) { super.handleMessage(message); } }.postDelayed(new Runnable() { @Override public void run() { while(true); } }, Long.MAX_VALUE >> 1); } View hButton = findViewById(R.id.h_button); hButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { createHandler(); nextActivity(); } }); |
از آنجایی که هیچ مقداری برای handleMessage ارسال نمی شود handler هیمنطور صبر می کند یعنی در بخش postDelayed می ماند و دیگر به خاطر while بیرون نمی آید.
سپس خطای زیر را خواهید دید.
6-Threads یا تردها
ترد هم همانند قبلی اگر درون آن یک حلقه بی انتها وجود داشته باشد خطا را باز خواهیم دید.
کد زیر را تست کنید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | void spawnThread() { new Thread() { @Override public void run() { while(true); } }.start(); } View tButton = findViewById(R.id.t_button); tButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { spawnThread(); nextActivity(); } }); |
و شکل زیر خطا را برای شما توصیف می کند.
7-TimerTask یا کار تایمر
بازم هم همانند Thread به مثال توجه کنید
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | void scheduleTimer() { new Timer().schedule(new TimerTask() { @Override public void run() { while(true); } }, Long.MAX_VALUE >> 1); } View ttButton = findViewById(R.id.tt_button); ttButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { scheduleTimer(); nextActivity(); } }); |
فقط شکل خطا متفاوت است.
8-Sensor Manager یا مدیتریت سنوسر ها
زمانی که ما یک سرویسی داریم که در هر لحظه توسط اون سرویس یک دیتای خاص بین اکتیویتی ها Broadcast می شود اگر این کار در هر ثانیه انجام شود به علت این که هم در background است و هم این سرویس در هر ثانیه اجرا می شود سبب Memory Leak می شود.
1 2 3 4 5 6 7 8 9 10 11 12 | void registerListener() { SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL); sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST); } View smButton = findViewById(R.id.sm_button); smButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { registerListener(); nextActivity(); } }); |
ممکن است نتوانید کد بالا را تست کنید زیر به یک سرویس نیاز دارد
و خطای نمایش داده شد برابر با زیر می شود.
همانطور که دید به چه راحتی ممکن است خطای memory Leak رخ دهد ما تنها 8 تا از عمده آنها را بررسی کردیم.
موفق باشید.
0 پاسخ به “Memory Leak یا کمبود حافظه چیست ؟”