【问题标题】:how android GC exactly works?android GC 究竟是如何工作的?
【发布时间】:2015-02-26 23:16:59
【问题描述】:

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

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

编辑:

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

通过使用 MAT,我发现问题在于 DecorView 对象,当我旋转屏幕 7 次时,应用程序因 OOM 崩溃,而 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);
    }
}

【问题讨论】:

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


    【解决方案1】:

    GC 正在清理您的对象,并且(实际上)您对此无能为力,这是语言属性(我认为这是很棒的功能)。你不必在“onFinish”中做任何事情,系统会为你清理东西,是的 - 你的所有对象,小部件等如果你想在设备旋转时保留一些数据(就像你说的那样 Activity 被破坏了参考)你可以使用onSaveInstanceState。有关针对 GC 保存数据的更多信息HERE

    【讨论】:

    • 我的问题是没有保存东西,我有内存泄漏问题。
    • 我的活动没有被破坏。
    • 告诉我你的清单中没有android:configChanges?而且您显示的代码没有泄漏。
    • 是的 GC 销毁 Activity 但是如果没有指向 Activity 的引用,那么代码中是否存在对 Activity 的引用(通过 textview)?
    • 使用 MAT 查看您的堆。并发布崩溃的 Activity 的代码。这不是 10,000 行。
    【解决方案2】:

    根据您的情况,您只想从之前的方向破坏之前的设置,对吗?

    最好的方法是 android:configChanges="orientation|screenSize"

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

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

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 1970-01-01
      • 2011-06-26
      • 2021-08-15
      • 2012-06-08
      • 2011-10-11
      • 2013-07-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多