android GC究竟如何工作?

时间:2014-12-30 19:34:40

标签: java android memory-leaks garbage-collection out-of-memory

我知道GC会处理没有引用它的对象,但我不知道它是如何工作的。 在这个简单的android代码中我们有一个活动和textview,我知道当屏幕旋转整个活动被破坏和android创建一个新的。 GC可以摧毁以前的活动吗? 是不是因为textview持有一个参考活动,整个活动从GC中存活? 我是否需要在完成活动(或类似的东西)上做一些事情来发布参考?

@Override
 protected void onCreate(Bundle state) {
   super.onCreate(state);
   TextView textview = new TextView(this);
   textview .setText("Leaks are bad");
   setContentView(textview );
 }

Edite:

这是我的代码。 MAT使用MAT: 最大的对象:com.android.internal.policy.impl.PhoneWindow $ DecorView

通过使用MAT我发现DecorView对象是问题,当我用OOM旋转屏幕7次app崩溃时,MAT报告中确实有7个DecorView对象。

package atsoft.law.reader;

import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;

import atsoft.law.R;
import atsoft.law.selecttext.NewHighlightDialog;

public class ReaderActivity extends BaseReaderActivity
{
    Bundle bundle;
    MainDialogFragment mainDialogFragment;
    NewHighlightDialog newHighlightDialog;




    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        bundle = getIntent().getExtras();
        setLawID(bundle.getInt("law_id", 0));
        setCurrentPage(bundle.getInt("madde_id", 0));
        mainDialogFragment = new MainDialogFragment();
        adapter.setMainDialogFragment(mainDialogFragment);


        requestLaw(lawID);

    }

/////////////////OnLawReceived//////////////
    @Override
    protected void OnLawReceived()
    {
        adapter.PrePairAdapter(getSupportFragmentManager(),null, this, lawID);
        viewPager.setAdapter(adapter);
        viewPager.setCurrentItem(getCurrentPage());

        Log.i("total", String.valueOf(Runtime.getRuntime().totalMemory()));
        Log.i("max", String.valueOf(Runtime.getRuntime().maxMemory()));
        Log.i("free", String.valueOf(Runtime.getRuntime().freeMemory()));
    }


    @Override
    protected void onSaveInstanceState(Bundle outState)
    {
        super.onSaveInstanceState(outState);
        outState.putInt("current_viewpager_page", viewPager.getCurrentItem());
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState)
    {
        super.onRestoreInstanceState(savedInstanceState);
        if(savedInstanceState != null)
        {
            setCurrentPage(savedInstanceState.getInt("current_viewpager_page", 0));
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event)
    {
        if(keyCode==KeyEvent.KEYCODE_MENU)
        {
            adapter.Prepair2();
            mainDialogFragment.Initialize(this, viewPager, adapter);
            mainDialogFragment.show(getSupportFragmentManager(),null);

            return true;
        }
        else if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
        {
            viewPager.setCurrentItem(viewPager.getCurrentItem()+1);
            return true;
        }
        else if(keyCode == KeyEvent.KEYCODE_VOLUME_UP)
        {
            viewPager.setCurrentItem(viewPager.getCurrentItem()-1);
            return true;
        }
        else if(keyCode == KeyEvent.KEYCODE_BACK)
        {
            if(mainDialogFragment.isAdded())
            {
                mainDialogFragment.dismiss();
            }
        }

        return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.reader, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings)
        {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }


    /////////ViewPager Page Events/////
    @Override
    public void onPageScrolled(int i, float v, int i2) {

    }

    @Override
    public void onPageSelected(int i) {

        if (newHighlightDialog != null) newHighlightDialog.dismissAndDeactivateTextSelector();
    }

    @Override
    public void onPageScrollStateChanged(int i) {

    }

    public NewHighlightDialog getHighlightDialog()
    {
        if(this.newHighlightDialog == null) this.newHighlightDialog = new NewHighlightDialog(this);
        return this.newHighlightDialog;
    }


    @Override
    protected void onDestroy()
    {
        Log.i("BaseReaderActivity", "onDestroy ");
        super.onDestroy();
        unbindDrawables(findViewById(R.id.root_in_readeractivity_layout));
        mainDialogFragment.releaseReference();
        mainDialogFragment = null;
        if(newHighlightDialog != null)
        {
            newHighlightDialog.realestReference();
            newHighlightDialog = null;
        }
        getAdapter().releaseReference();

        System.gc();


    }
    private void unbindDrawables(View view) {
        if (view.getBackground() != null)
            view.getBackground().setCallback(null);

        if (view instanceof ImageView) {
            ImageView imageView = (ImageView) view;
            imageView.setImageBitmap(null);
        } else if (view instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup) view;
            for (int i = 0; i < viewGroup.getChildCount(); i++)
                unbindDrawables(viewGroup.getChildAt(i));

            if (!(view instanceof AdapterView))
                viewGroup.removeAllViews();
        }
    }
}










public abstract class BaseReaderActivity extends ActionBarActivity implements OnThreadFinishListener, ViewPager.OnPageChangeListener
{



    protected int lawID = 0;
    protected int vpCurrentPage = 0;
    protected FragmentAdapter adapter;
    protected ViewPager viewPager;
    private GlobalData globalData;
    ProgressDialog progressDialog;



    private void Init()
    {
        globalData= (GlobaData) this.getApplicationContext();
        adapter = FragmentAdapter.getInstance(getSupportFragmentManager());
        viewPager = (ViewPager) findViewById(R.id.vp);
        viewPager.setOnPageChangeListener(this);
        progressDialog = new ProgressDialog(this);
    }

    protected FragmentAdapter getAdapter()
    {
        return FragmentAdapter.getInstance(getSupportFragmentManager());
    }

    protected ViewPager getPager()
    {
        return this.viewPager;
    }
    protected GlobalStack getGlobalData()
    {
        return this.globalData;
    }
    protected DbCenter getDb()
    {
        return DbCenter.getInstance(this);
    }

    protected void setLawID(int id)
    {
        this.lawID = id;
    }
    protected int getLawID()
    {
        return this.lawID;
    }
    protected void setCurrentPage(int page)
    {
        this.vpCurrentPage = page;
    }
    protected int getCurrentPage()
    {
        return this.vpCurrentPage;
    }
    protected void requestLaw(int lawID)
    {

        if(!getGlobalData().checkLawAvailability(lawID))
        {

            this.UploadLawToGlobalData(lawID);
            return;
        }
        else
        {

            this.OnLawReceived();
        }
    }

    protected abstract void OnLawReceived();
    protected void UploadLawToGlobalData(int lawID)
    {
        progressDialog.setText(LawIDs.getFaNameById(lawID));
        progressDialog.show();

        getDb().Prepair(lawID, this);
    }
    public Law getCurrentLaw()
    {
        return getGlobalData().getTheLaw();
    }
    @Override
    public void threadFinished() throws IOException, XmlPullParserException
    {
        getGlobalData().UploadToGlobalData(getDb().getLaw());
        this.OnLawReceived();
        Log.i("BaseReaderActivity","upload completed !");
        Log.i("BaseReaderActivity", "OnLawReceived");
        progressDialog.hide();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        getSupportActionBar().hide();
        setContentView(R.layout.activity_main_);
        Init();
        getGlobalData().Init();

        viewPager.setOffscreenPageLimit(2);
        viewPager.setSoundEffectsEnabled(true);
        adapter.setViewPager(viewPager);
    }
}

2 个答案:

答案 0 :(得分:0)

GC正在清理你的物品,并且(在实践中)你无法做任何事情,这是语言属性(在我看来很棒的功能)。你不必在&#34; onFinish&#34;中做任何事情,系统会为你清理东西,是的 - 所有你的对象,小部件等等,如果你想在设备旋转时保留一些数据(就像你一样)说活动被销毁,所有它的引用都可以使用onSaveInstanceState。有关针对GC保存数据的更多信息HERE

答案 1 :(得分:0)

根据您的情况,您只想破坏先前方向的先前设置,对吧?

最好的方法是     机器人:configChanges = “取向|屏幕尺寸”

主题问题,请查看此Why is it bad practice to call System.gc()?

在你的应用程序中调用system.gc,你无法控制收集器在你的应用程序中杀死什么,这可能会导致很多麻烦,比如nullpointers等。

相关问题