2011-08-29 16 views
8

मैं एंड्रॉइड में एक गेम बना रहा हूं, और मैंने देखा कि गेम में मेमोरी रिसाव है। Iv मेमोरी रिसाव को एक छोटे से एप्लिकेशन में अलग करने में कामयाब रहा ताकि मैं इसे ठीक करने का प्रयास कर सकूं और काम कर सकूं।एंड्रॉइड सर्फेसव्यू थ्रेड और मेमोरी लीक

एप्लिकेशन अपने दृश्य के लिए एक सतही दृश्य का उपयोग करता है और स्क्रीन पर सभी ड्राइंग करने के लिए उस से जुड़ा धागा है। मेमोरी रिसाव तब होता है जब मैं एक नई गतिविधि शुरू करता हूं और वर्तमान में उपयोग कर रहा हूं। मैं इसे देख सकता हूं जब मैं अपने टेस्ट एप्लिकेशन पर मेमोरी डंप करता हूं क्योंकि यह सब कुछ करता है और एक गतिविधि बंद करता है (गतिविधि ए -> गतिविधि बी -> गतिविधि ए)। Iv तरह के विचारों से बाहर निकल गया कि मैं इसे कैसे ठीक कर सकता हूं क्योंकि iv ने मेरे सभी संदर्भों को नकारने का प्रयास किया है जो मैं दृश्य (थ्रेड के अंदर) में बना हूं, iv ने दृश्य को नष्ट करने पर सतह दृश्य से कॉलबैक को हटाने का प्रयास किया, और यह भी गतिविधि के अंदर, यह कोई फर्क नहीं पड़ता है।

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)); 
    } 
} 

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-- मैं अपने surfaceDestroyed (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 void surfaceCreated(SurfaceHolder holder) { 
     if(!this.vThread.isAlive()) { 
      this.vThread =new MemoryLeakViewThread(); 
      this.vThread.setRunning(true, this); 
      this.vThread.start(); 
     } 
    } 

को surfaceCreated (SurfaceHolder धारक) विधि को बदलने की जरूरत है कि हम बदलने की जरूरत है निम्नलिखित

public MemoryLeakViewThread() { 
    } 

    public void setRunning(boolean run) { 
     this.run =run; 
    } 

    public void setRunning(boolean run, MemoryLeak view) { 
     this.run =run; 
     this.view =view; 
    } 

ऐसा करने से यह समस्या को ठीक करने लग रहा था, थ्रेड क्लास और थ्रेड ग्रुप के कारण थ्रेड केवल स्मृति में रहने लगता है। लेकिन मुझे लगता है कि यह डीबगर के कारण हो सकता है।

+0

अपवाद और स्टैक-ट्रेस जोड़ना इस मुद्दे को जानने में मदद करेगा। – Arslan

+0

Iv थ्रेड की चलती स्थिति सेट करते समय दृश्य को पार करके अधिकांश मेमोरी लीक समस्याओं को ठीक करने में कामयाब रहा, और फिर जब मैं चल रहा स्थिति को गलत पर सेट करता हूं तो उसे शून्य पर सेट करता हूं। इसने स्मृति से दोनों गतिविधियों को हटा दिया है और अब स्मृति से एकमात्र चीज है जो धागा है जो थ्रेड ग्रुप क्लास के अंदर फंस जाता है। मुझे याद है कि वहां धागे के बारे में कुछ पढ़ना होगा अगर वहां शुरू नहीं हुआ तो मैं अभी इसे लिंक नहीं ढूंढ सकता। – Spider

+0

http://code.google.com/p/android/issues/detail?id=7979 यह है कि। स्टैक-ट्रेस के लिए, आप मुझे अपवाद जोड़ने के लिए कहां चाहते हैं? यह किसी भी फेंक नहीं रहा है, ठीक है जब यह स्मृति से बाहर हो जाएगा, लेकिन जैसा कि मैं अपने परीक्षण आवेदन के साथ ज्यादा मेमोरी का उपयोग नहीं कर रहा हूं, इसमें कुछ समय लगेगा। मैं एक ढेर डंप का विश्लेषण करने के लिए MAT का उपयोग कर रहा हूं, इसलिए मैं देख सकता हूं कि स्मृति में क्या हो रहा है – Spider

उत्तर

5

जब आप इसे सृजनशील बनाते हैं तो आपको कन्स्ट्रक्टर में नया थ्रेड नहीं बनाना चाहिए। अपने कोड की तुलना मेरे उदाहरण से करें: How can I use the animation framework inside the canvas?

+0

ने जो कहा आपने कोशिश की और कन्स्ट्रक्टर विधि से धागे के निर्माण को हटा दिया और इसके बजाय सतह के अंदर की सतह के अंदर रखा। इसने धागे को स्मृति में फंसने से रोक दिया। : डी मेरे सभी मेमोरी मुद्दों को अभी तय कर रहे हैं। – Spider

-1

आप यहाँ देख सकते हैं:

http://developer.android.com/resources/articles/avoiding-memory-leaks.html

सबसे आसान तरीका है एंड्रॉयड में एक स्मृति रिसाव शुरू करने के लिए एक दृश्य के निर्माता आवेदन संदर्भ के बजाय पूरे गतिविधि पारित करने के लिए है। इस एक में

setContentView(new MemoryLeak(this)); 

: आप इस लाइन को बदलने की कोशिश की है

setContentView(new MemoryLeak(Context.getApplicationContext())); 

?

उम्मीद है कि यह मदद करता है।

+1

ठीक है आपने स्पष्ट रूप से इसे आजमाया नहीं है, या आपने देखा होगा कि जब आप एक गैर स्थैतिक विधि के स्थिर संदर्भ को संकलित करने का प्रयास करते हैं तो क्या होता है। – NickT

संबंधित मुद्दे