Falando sobre Android: essas coisas sobre otimização de memória~

Acredito que no processo de desenvolvimento, o framework de código aberto LeakCanary é mais usado pelos meus amigos para monitorar os pontos problemáticos de vazamentos de memória. Isso é mais eficiente e os pontos problemáticos podem ser encontrados rapidamente, seguidos pelo processamento de otimização correspondente, mas Afinal, LeakCanary é uma estrutura de código aberto. , por motivos especiais, pode não permitir o uso da estrutura de código aberto LeakCanary para analisar possíveis vazamentos de memória. Portanto, geralmente usamos ferramentas de análise de memória para detectar possíveis cenários de vazamento de memória.

Usamos as ferramentas de análise Memory Profiler e MAT para detectar se o aplicativo tem vazamentos de memória.

Primeiro código fonte:

Atividade do Monitor de Memória:

public class MemoryMonitorActivity extends BaseActivity{
@BindView(R.id.btnMemoryThrashing)
Button btnMemoryThrashing;
@BindView(R.id.btnHanlder)
Button btnHanlder;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.memory_monitor_activity);
    ButterKnife.bind(this);
}
@OnClick({R.id.btnMemoryThrashing,R.id.btnHanlder})
public void onViewClicked(View view) {
    switch (view.getId()){
        case R.id.btnMemoryThrashing:
            SingleManager.getInstance(this).get();
            break;
        case R.id.btnHanlder:
           sendMsg();
            break;
    }
}

private void sendMsg(){
    mHandler.postDelayed(runnable,5000);
}
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        Message message = new Message();
        message.what=1;
        message.obj = "子线程发消息";
        mHandler.sendMessage(message);
    }
};
}
复制代码

Gerente Único:

private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
         switch (msg.what){
             case 1:
                 Toast.makeText(MemoryMonitorActivity.this,"主线程接收: "+msg.obj,Toast.LENGTH_LONG).show();
                 break;
         }
    }
};}SingleManager:public class SingleManager {

  private static SingleManager instance = null;

  private  Context context = null;

  private SingleManager(Context context){
      this.context = context;
  }
  public static SingleManager getInstance(Context context){
      if (instance==null){
          instance = new SingleManager(context);
      }
      return instance;
  }

  public void get(){
      LogUtils.e(" logcat context:  "+ context );
  }
  }
复制代码

Como pode ser visto no código-fonte, exemplos de vazamentos de memória causados ​​pelo modo singleton, Handler e classes internas anônimas não falarão sobre as causas dos vazamentos de memória desta vez e usarão a ferramenta Memory Profiler para analisá-los.

Como pode ser visto na figura acima, a interface MemoryMonitorActivity foi encerrada ou destruída, mas a instância MemoryMonitorActivity ainda existe e o tamanho de seu próprio objeto de instância é 0,69 K, e o MemoryMonitorActivity incluindo o tamanho de referência é 142,7 K, que é um vazamento de memória típico da atividade e há desperdício de memória. Mas através do exposto, ainda não conseguimos localizar a real causa do vazamento de memória da atividade. Em seguida, continue a olhar para a imagem a seguir:

Pelo exposto, pode-se perceber que:

1. O contexto contém uma referência externa MemoryMonitorActivity, que faz com que o GC falhe ao reciclar.

2. O executável contém uma referência externa MemoryMonitorActivity.No código-fonte, pode-se ver que executável é uma classe interna que contém uma referência externa à classe MemoryMonitorActivity, o que faz com que o GC falhe na reciclagem.

3. O manipulador mantém a referência externa de MemoryMonitorActivity, que faz com que o GC falhe ao reciclar.

Nos três pontos acima, o verdadeiro motivo do vazamento de memória da atividade é que ela mantém a referência, o GC não a recicla a tempo e há um desperdício de memória.

那接下来怎么优化它呢,别着急。我们知道如何使用Memory Profiler来检测应用是否存在内存泄漏。接下来我们使用MAT来分析下内存占用情况。

我们点击Top Consumers看看,如下:

从上图可以看出,由于MemoryMonitorActivity界面已经销毁了,仍然存在很多实例,因此它已经存在内存泄露了。我们需要熟悉Memory Profiler和 MAT工具的使用,可以进行综合分析来定位内存泄露的真正原因。

接下来我们就需要优化代码了。

优化后源码如下:

MemoryMonitorActivity:

public class MemoryMonitorActivity extends BaseActivity{
@BindView(R.id.btnMemoryThrashing)
Button btnMemoryThrashing;
@BindView(R.id.btnHanlder)
Button btnHanlder;

private MyHandler myHandler;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.memory_monitor_activity);
    ButterKnife.bind(this);
    myHandler = new MyHandler(this);
}
@OnClick({R.id.btnMemoryThrashing,R.id.btnHanlder})
public void onViewClicked(View view) {
    switch (view.getId()){
        case R.id.btnMemoryThrashing:
            SingleManager.getInstance(this).get();
            break;
        case R.id.btnHanlder:
            sendMsg();
            break;
    }
}

private void sendMsg(){
    myHandler.postDelayed(runnable,5000);
}

/**
 * 匿名内部类持有外部类,需要实例化一个Runnable对象,在onDestroy方法runnable设置null即可
 */
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        Message message = new Message();
        message.what=1;
        message.obj = "子线程发消息";
        myHandler.sendMessage(message);
    }
};

/**
 * 使用静态handler的弱引用方式来避免内存泄露
 */
private static class MyHandler extends Handler{
    private final WeakReference<MemoryMonitorActivity> memoryMonitorActivity;
    public MyHandler(MemoryMonitorActivity activity){
        memoryMonitorActivity = new WeakReference<>(activity);
    }
    @Override
    public void handleMessage(Message msg) {
        MemoryMonitorActivity activity = memoryMonitorActivity.get();
        super.handleMessage(msg);
        if (activity==null)return;
        switch (msg.what){
            case 1:
                Toast.makeText(activity,"主线程接收: "+msg.obj,Toast.LENGTH_LONG).show();
                break;
        }
    }
}
@Override
protected void onDestroy() {
    super.onDestroy();
    if (runnable!=null){
        runnable=null;
    }
    if (myHandler!=null){
        myHandler.removeCallbacksAndMessages(null);
        myHandler=null;
    }
}
}
复制代码

SingleManager:

  public class SingleManager {
  private static SingleManager instance = null;

  private  Context context = null;

  private SingleManager(Context context){
      this.context = context;
  }
  public static SingleManager getInstance(Context context){
      if (instance==null){
          // FIXME: 2021/10/30 使用context.getApplicationContext()和app生命周期一样长的进行避免内存泄露
          instance = new SingleManager(context.getApplicationContext());
      }
      return instance;
  }

  public void get(){
      LogUtils.e(" logcat context:  "+ context );
  }
  }
复制代码

经过代码优化,通过Memory Profiler和 MAT工具分析结果,MemoryMonitorActivity不存在内存泄露了。

作为Android开发者,我们需要必备这个基本技能,需要熟悉Memory Profiler和 MAT内存工具的使用,开发过程中会经常使用到的。

Acho que você gosta

Origin juejin.im/post/7084594001516445710
Recomendado
Clasificación