게임을 안드로이드로 생성하면 게임에 메모리 누수가있는 것으로 나타납니다. Iv는 메모리 누수를 작은 응용 프로그램으로 격리하여 잘 보면서 해결할 수 있도록했습니다.Android Surfaceview 스레드 및 메모리 누출
응용 프로그램이보기에 표면보기를 사용하고 모든 그림을 화면에 표시하기 위해 스레드에 첨부되어 있습니다. 새 액티비티를 시작하고 현재 사용중인 메신저를 닫으면 메모리 누수가 발생합니다. 모든 것이 열려 있고 활동 (활동 a -> 활동 b -> 활동 a)이므로 내 테스트 응용 프로그램에서 메모리 덤프를 할 때 이것을 볼 수 있습니다. 이베 일종의 아이디어가 다 떨어졌을 때 iv에서 이것을 고칠 수 있었는데 뷰에서 (thread 내에서) 만드는 모든 참조를 null로 만들려고했는데 iv는 뷰를 파괴 할 때 콜백을 surfaceview에서 제거하려고 시도했다. 활동 내에서는 어떤 차이도없는 것처럼 보입니다.
MemoryLeakActivity.java
package memory.leak;
import memory.leak.view.MemoryLeak;
import android.app.Activity;
import android.os.Bundle;
public class MemoryLeakActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MemoryLeak(this));
}
}
MemoryLeakViewThread.java
package memory.leak.thread;
import memory.leak.view.MemoryLeak;
import android.view.SurfaceHolder;
import android.graphics.Canvas;
public class MemoryLeakViewThread extends Thread {
private MemoryLeak view;
private boolean run =false;
public MemoryLeakViewThread(MemoryLeak view) {
this.view =view;
}
public void setRunning(boolean run) {
this.run =run;
}
@Override
public void run() {
Canvas canvas =null;
SurfaceHolder holder =this.view.getHolder();
while(this.run) {
canvas =holder.lockCanvas();
if(canvas !=null) {
this.view.onDraw(canvas);
holder.unlockCanvasAndPost(canvas);
}
}
holder =null;
this.view =null;
}
}
MemoryLeak.java
package memory.leak.view;
import memory.leak.TestActivity;
import memory.leak.thread.MemoryLeakViewThread;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.GestureDetector.OnGestureListener;
public class MemoryLeak extends SurfaceView implements SurfaceHolder.Callback, OnGestureListener {
private GestureDetector gesture;
private MemoryLeakViewThread vThread;
private Context context;
public MemoryLeak(Context context) {
super(context);
this.getHolder().addCallback(this);
this.vThread =new MemoryLeakViewThread(this);
this.gesture =new GestureDetector(this);
this.context =context;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
public void surfaceCreated(SurfaceHolder holder) {
if(!this.vThread.isAlive()) {
this.vThread =new MemoryLeakViewThread(this);
this.vThread.setRunning(true);
this.vThread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
if(this.vThread.isAlive()) {
this.vThread.setRunning(false);
while(retry) {
try {
this.vThread.join();
retry =false;
} catch(Exception ee) {}
}
}
this.vThread =null;
this.context =null;
}
public boolean onTouchEvent(MotionEvent event) {
return this.gesture.onTouchEvent(event);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
}
@Override
public void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {}
@Override
public boolean onSingleTapUp(MotionEvent e) {
Intent helpScreenIntent =new Intent(this.context, TestActivity.class);
this.context.startActivity(helpScreenIntent);
if (this.context instanceof Activity)
((Activity) this.context).finish();
return true;
}
}
TestActivity.java
package memory.leak;
import memory.leak.view.Test;
import android.app.Activity;
import android.os.Bundle;
public class TestActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new Test(this));
}
}
이 뷰를 설정되도록 0
TestViewThread.java
package memory.leak.thread;
import memory.leak.view.Test;
import android.view.SurfaceHolder;
import android.graphics.Canvas;
public class TestViewThread extends Thread {
private Test panel;
private boolean run =false;
public TestViewThread(Test panel) {
this.panel =panel;
}
public void setRunning(boolean run) {
this.run =run;
}
@Override
public void run() {
Canvas canvas =null;
SurfaceHolder holder =this.panel.getHolder();
while(this.run) {
canvas =holder.lockCanvas();
if(canvas !=null) {
this.panel.onDraw(canvas);
holder.unlockCanvasAndPost(canvas);
}
}
holder =null;
this.panel =null;
}
}
Test.java
package memory.leak.view;
import memory.leak.MemoryLeakActivity;
import memory.leak.thread.TestViewThread;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.GestureDetector.OnGestureListener;
public class Test extends SurfaceView implements SurfaceHolder.Callback, OnGestureListener {
private GestureDetector gesture;
private TestViewThread vThread;
private Context context;
public Test(Context context) {
super(context);
this.getHolder().addCallback(this);
this.vThread =new TestViewThread(this);
this.gesture =new GestureDetector(this);
this.context =context;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
public void surfaceCreated(SurfaceHolder holder) {
if(!this.vThread.isAlive()) {
this.vThread =new TestViewThread(this);
this.vThread.setRunning(true);
this.vThread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
if(this.vThread.isAlive()) {
this.vThread.setRunning(false);
while(retry) {
try {
this.vThread.join();
retry =false;
} catch(Exception ee) {}
}
}
this.vThread =null;
this.context =null;
}
public boolean onTouchEvent(MotionEvent event) {
return this.gesture.onTouchEvent(event);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
}
@Override
public void onDraw(Canvas canvas) {
canvas.drawColor(Color.RED);
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {}
@Override
public boolean onSingleTapUp(MotionEvent e) {
Intent helpScreenIntent =new Intent(this.context, MemoryLeakActivity.class);
this.context.startActivity(helpScreenIntent);
if (this.context instanceof Activity)
((Activity) this.context).finish();
return true;
}
}
--Edit-- 는 I는 surfaceDestroyed (SurfaceHolder에 홀더)의 뷰 클래스를 변경 한 스레드가 중지하라는 메시지를 표시 할 때 스레드가 null이되어야합니다. 내가 만든 변화는 우리가 바꿀 필요가 당신은 또한 스레드 클래스에 다음
public void surfaceCreated(SurfaceHolder holder) {
if(!this.vThread.isAlive()) {
this.vThread =new MemoryLeakViewThread();
this.vThread.setRunning(true, this);
this.vThread.start();
}
}
에 surfaceCreated (SurfaceHolder에 홀더) 방법을 변경해야
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
if(this.vThread.isAlive()) {
this.vThread.setRunning(false);
while(retry) {
try {
this.vThread.join();
retry =false;
} catch(Exception ee) {}
}
this.vThread.setRunning(false, null);
}
this.vThread =null;
this.context =null;
this.gesture =null;
}
수있는 다음
public MemoryLeakViewThread() {
}
public void setRunning(boolean run) {
this.run =run;
}
public void setRunning(boolean run, MemoryLeak view) {
this.run =run;
this.view =view;
}
이렇게하면 문제가 해결되는 것처럼 보였습니다. 유일한 문제는 스레드가 스레드 클래스와 스레드 그룹으로 인해 메모리에 남아있는 것처럼 보입니다. 하지만이 생각은이 디버거로 인해 수도 있습니다.
예외 및 스택 추적을 추가하면 문제를 파악하는 데 도움이됩니다. – Arslan
Iv는 스레드의 실행 상태를 설정할 때 뷰를 전달하고 실행 상태를 false로 설정하면이를 null로 설정하여 대부분의 메모리 누수 문제를 해결할 수있었습니다. 이것은 메모리에서 액티비티와 뷰를 모두 제거 했으므로 머물러있는 유일한 것은 쓰레드 그룹 클래스에 갇혀있는 쓰레드입니다. 나는 스레드가 시작되지 않았다면 거기에 갇히게 될 것이라는 것을 읽은 것을 기억한다. 나는 지금 막 그것에 대한 링크를 찾을 수 없다. – Spider
http://code.google.com/p/android/issues/detail?id=7979 thats it. 스택 추적에 관해서는 어디에서 예외를 추가할까요? 그것은 아무 것도 던지지 않고 있습니다. 결국 메모리가 부족 해지면 좋겠지 만, 테스트 애플리케이션으로 많은 메모리를 사용하지 않으므로 시간이 걸릴 것입니다. 메신저를 사용하여 힙 덤프를 분석하여 메모리에 갇혀있는 것을 볼 수 있습니다. – Spider