【问题标题】:Probable android memory leak可能的android内存泄漏
【发布时间】:2017-01-09 18:53:02
【问题描述】:

我有这个 android 项目,无法确定它为什么会占用内存?请注意,仅填充 RAM 不会进行任何处理。我已阅读 Android RAM issueshow to solve,但不知道该怎么做。我对android和java都是新手。

刚刚注意到(在 Android Monitor - RAM 中)我的应用仅使用 4MB 内存。 如果有人尝试运行(请执行 - MainActivity 是启动器,而 MyCanvas 只是用作视图的类),我可以使用高达 100 的速度变量(甚至更多),在 10 毫秒或更频繁地进行线程回调 -它没有问题。但是一旦我触摸并移动垃圾收集器就会暂停一切。

MyCanvas.java(用作视图)

package com.abc.mygraphics;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;

import java.util.Random;
import android.os.Handler;

public class MyCanvas extends View {

public static Paint paint;
//public static int n = 5000;
public static int N = 100, particleSize = 3;
public static int height, width;
public static float[][] pos = new float[N][2];
public static float[][] pos0 = new float[N][2];
//public static float distX, distY, dist;
Handler handler = new Handler();
public static int speed = 1;
public static int gravityX, gravityY;
public static Random random = new Random();
public static int[] colorList = new int[10];
public static int sphereSize = 100, M = 10;
public static float[] distance = new float[N];
public static int[][] gravity = new int[N][2];
public static boolean[] direction = new boolean[N];
public static int[] moved = new int[N];

public MyCanvas(Context context) {
    super(context);

    width = MainActivity.sharedPreferences.getInt("screenX", 200);
    height = MainActivity.sharedPreferences.getInt("screenY", 200);
    colorList = new int[]{Color.RED, 0xffff4000, 0xffffff00, 0xff40ff00, 0xff00ff00, 0xff00ff80, 0xff0080ff, 0xff0000ff, 0xffbf00ff, 0xffff0040};

    paint = new Paint();
    paint.setColor(Color.GRAY);
    int i;
    for (i = 0; i < N; i++) {
        pos[i][0] = random.nextInt(width);
        pos[i][1] = random.nextInt(height);
        pos0[i][0] = pos[i][0];
        pos0[i][1] = pos[i][1];
        moved[i] = 0;
        direction[i] = true;
    }

    final Runnable r = new Runnable() {
        public void run() {
            invalidate();
            handler.postDelayed(this, 100);
        }
    };
    handler.postDelayed(r, 100);
}

public static void changeGravity(){
    gravityX = MainActivity.sharedPreferences.getInt("x",200);
    gravityY =   MainActivity.sharedPreferences.getInt("y",200);
    // gravityY -= 68;
    for(int i=0;i<N;i++){
        calcDist(i);
    }
}

@Override
public void onDraw(Canvas canvas){
    int i;
    int x;  //remove at some poitnt
    canvas.drawColor(Color.BLACK);
    //canvas.drawCircle(gravityX,gravityY, 50, paint);

    for(i=0;i<N;i++) {
        setPosition(i);
        x =  random.nextInt(10);
        paint.setColor(colorList[x]);
        canvas.drawCircle(pos[i][0], pos[i][1], particleSize, paint);
    }
}

public static void setPosition(int i){
    // this is wrong
    if(moved[i] >= (int)distance[i]/speed){
        direction[i] = !direction[i];
        setGravity(i);
    }
    else{
        pos[i][0] = pos0[i][0] + speed*moved[i]*(gravity[i][0]- pos0[i][0])/distance[i];
        pos[i][1] = pos0[i][1] + speed*moved[i]*(gravity[i][1]- pos0[i][1])/distance[i];
        moved[i]++;
    }
}

public static void calcDist(int i){
    setGravity(i);
    distance[i] = (float) Math.sqrt( Math.pow((gravity[i][0]-pos[i][0]),2) +  Math.pow((gravity[i][1]-pos[i][1]),2) );
}

public static void setGravity(int i){

    // do not forget to set pos0 in both cases
    if(direction[i]){
        gravity[i][0] = gravityX;
        gravity[i][1] = gravityY;
    }

    else{
        // make this biased on radius of sphere
        gravity[i][0] =  random.nextInt(width);
        gravity[i][1]  = random.nextInt(height);
    }
    pos0[i][0] = pos[i][0];
    pos0[i][1]  = pos[i][1];
    moved[i]=0;
}



}

主Activity.java

package com.abc.mygraphics;

 import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.Window;
import android.view.WindowManager; 
import android.widget.EditText;
import android.widget.TextView;

import com.abc.mygraphics.MyCanvas;

import org.w3c.dom.Text;

public class MainActivity extends AppCompatActivity {

//DrawingView dr = new DrawingView(this);

public  static SharedPreferences sharedPreferences;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);


    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    int height = displaymetrics.heightPixels;
    int width = displaymetrics.widthPixels;


    sharedPreferences = getSharedPreferences( getPackageName() + "_preferences", MODE_PRIVATE);

    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.putInt("screenX",width);
    editor.putInt("screenY", height);
    editor.putInt("x", 200);
    editor.putInt("y", 200);
    editor.commit();
    setContentView(new MyCanvas(this));
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    // int x = (int)event.getX();
    //int y = (int)event.getY();
    int x = (int) event.getRawX();
    int y = (int) event.getRawY();
    //sharedPreferences = getSharedPreferences("CheckSharing",Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.putInt("x", x);
    editor.putInt("y", y);
    editor.apply();
    MyCanvas.changeGravity();

    return false;
}

}

【问题讨论】:

  • 看起来您在MyView 中的Handler 可能会泄漏MyView 类,然后由于您使用Handler.postDelayed 的方式,它也会泄漏与之关联的Activity。尝试暂时注释掉 Handler 的使用,看看内存问题是否仍然存在(假设这是代码中唯一的泄漏)。如果不是,那么我们可以讨论一些可能的修复方法。
  • 另外,根据您的编辑,如果我的猜测是正确的,那么当您在纵向和横向模式之间来回旋转设备时,内存使用量应该会继续增加,从而导致托管自定义活动的新实例每次都会创建视图。
  • 比我用什么代替处理程序??。坦率地说,我不知道线程的工作我使用它只是因为它做我想要的。因为我需要不断刷新View。我想要的是一个像粒子流这样的应用程序(在 Play 商店中搜索)。
  • 您可以尝试使用具有弱引用视图的静态处理程序,如here 所述。问题/答案是在Service 中讨论Handler,但它仍然适用于View 中的一个。或者,将Handler 移动到托管视图的ActivityFragment 以及活动暂停时remove the callback。您可以在活动恢复时添加回调。

标签: android memory memory-leaks


【解决方案1】:

有我的问题。 每次发生触摸事件时,我都试图调用我的方法,这是我们无法做到的,因为当您拖动鼠标时,实际上会发生数千个(可能更多)触摸事件。

尝试从代码中理解。在主要活动中,我们有我们的 onTouch 事件侦听器,它调用 changeGravity() 方法,该方法又调用 calcDist() 和 setGravity() (来自 calcDist() )。所以产生了很多垃圾,因此 GC 开始发挥作用,它暂停了应用程序,一切似乎都挂了。

解决方案 - 只需将 calcDist() 调用放在线程内,因此无论重力如何,都将在 10 毫秒内生效。与我们从 changeGravity() 方法调用时发生的情况相比,这是我们的模拟器和手机能够做到的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-23
    • 1970-01-01
    相关资源
    最近更新 更多