java – Android GC注意事项 – GC何时运行,并可以从代码跟踪其运行状态?

前端之家收集整理的这篇文章主要介绍了java – Android GC注意事项 – GC何时运行,并可以从代码跟踪其运行状态?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我现在一直在寻找一些描述Dalvik VM垃圾收集器架构的详细设计文档,但还没有变得太多.考虑到GC运行的性能影响,我真的希望更好地了解5个具体问题:
1.什么在 Android中触发GC?我看到的其他VM实现通常允许在GC接收到运行信号之前将一定百分比的系统内存分配给应用程序.扫描以下LogCat似乎显示Dalvik GC至少部分经常运行 –
12-14 11:34:57.753: D/dalvikvm(279): GC_EXTERNAL_ALLOC freed 735 objects / 54272 bytes 
in 90ms
12-14 11:34:57.893: D/dalvikvm(279): GC_EXTERNAL_ALLOC freed 256 objects / 12240 bytes 
in 61ms
12-14 11:34:57.943: I/jPCT-AE(279): Loading Texture...
12-14 11:34:57.993: D/dalvikvm(279): GC_FOR_MALLOC freed 65 objects / 2840 bytes in 
52ms
12-14 11:34:58.013: I/dalvikvm-heap(279): Grow heap (frag case) to 5.039MB for 
1048592-byte allocation
12-14 11:34:58.073: D/dalvikvm(279): GC_FOR_MALLOC freed 1 objects / 40 bytes in 59ms
12-14 11:34:58.243: D/dalvikvm(279): GC_EXTERNAL_ALLOC freed 11 objects / 432 bytes in 
55ms
12-14 11:34:58.283: I/jPCT-AE(279): Loading Texture...
12-14 11:34:58.333: D/dalvikvm(279): GC_FOR_MALLOC freed 10 objects / 416 bytes in 46ms
12-14 11:34:58.344: I/dalvikvm-heap(279): Grow heap (frag case) to 6.040MB for  
1048592-byte allocation
12-14 11:34:58.423: D/dalvikvm(279): GC_FOR_MALLOC freed 2 objects / 80 bytes in 75ms
12-14 11:34:58.563: D/dalvikvm(279): GC_EXTERNAL_ALLOC freed 10 objects / 384 bytes in 
47ms
12-14 11:34:58.603: I/jPCT-AE(279): Loading Texture...
12-14 11:34:58.653: D/dalvikvm(279): GC_FOR_MALLOC freed 11 objects / 464 bytes in 44ms
12-14 11:34:58.663: I/dalvikvm-heap(279): Grow heap (frag case) to 7.040MB for 
1048592-byte allocation
12-14 11:34:58.743: D/dalvikvm(279): GC_FOR_MALLOC freed 2 objects / 80 bytes in 75ms
12-14 11:34:58.973: I/System.out(279): started document!
...
12-14 11:43:05.393: I/jPCT-AE(279): Memory usage before compacting: 5867 KB used out 
of 6215 KB
12-14 11:43:05.453: D/dalvikvm(279): GC_EXPLICIT freed 2560 objects / 145712 bytes in 
61ms
12-14 11:43:05.503: D/dalvikvm(279): GC_EXPLICIT freed 295 objects / 21448 bytes in 
51ms
12-14 11:43:05.717: I/jPCT-AE(279): Memory usage after compacting: 5705 KB used out of 
6215 KB
...
12-14 11:43:05.792: D/dalvikvm(279): GC_EXTERNAL_ALLOC freed 105 objects / 6152 bytes 
in 56ms
12-14 11:43:05.855: D/dalvikvm(279): GC_FOR_MALLOC freed 3 objects / 80 bytes in 51ms
...
12-14 11:43:12.863: D/dalvikvm(279): GC_EXTERNAL_ALLOC freed 864 objects / 1099072 
bytes in 70ms
12-14 11:43:13.053: D/dalvikvm(279): GC_EXTERNAL_ALLOC freed 45 objects / 1760 bytes 
in 55ms
12-14 11:43:14.533: D/dalvikvm(279): GC_EXTERNAL_ALLOC freed 49 objects / 2376 bytes 
in 58ms
12-14 11:43:14.933: D/dalvikvm(279): GC_EXTERNAL_ALLOC freed 34 objects / 1408 bytes 
in 55ms
12-14 11:43:15.423: D/dalvikvm(279): GC_EXTERNAL_ALLOC freed 13 objects / 504 bytes in 
58ms
12-14 11:43:15.953: D/dalvikvm(279): GC_EXTERNAL_ALLOC freed 13 objects / 520 bytes in 
56ms
...
12-14 11:43:31.203: I/jPCT-AE(279): Visibility lists disposed!
12-14 11:43:31.203: I/jPCT-AE(279): All texture data unloaded from gpu!
12-14 11:43:31.203: I/jPCT-AE(279): Renderer disposed!
12-14 11:43:31.203: I/jPCT-AE(279): Static references cleared...
...
12-14 11:43:36.943: E/dalvikvm-heap(279): 2964320-byte external allocation too large 
for this process.
12-14 11:43:36.953: E/GraphicsJNI(279): VM won't let us allocate 2964320 bytes
12-14 11:43:36.953: D/AndroidRuntime(279): Shutting down VM
12-14 11:43:36.953: W/dalvikvm(279): threadid=1: thread exiting with uncaught 
exception (group=0x4001d800)
12-14 11:43:36.973: E/AndroidRuntime(279): FATAL EXCEPTION: main
12-14 11:43:36.973: E/AndroidRuntime(279): android.view.InflateException: Binary XML 
file line #33: Error inflating class <unknown>
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.view.LayoutInflater.createView(LayoutInflater.java:513)
12-14 11:43:36.973: E/AndroidRuntime(279):  at
com.android.internal.policy.impl.PhoneLayoutInflater.
onCreateView(PhoneLayoutInflater.java:56)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:563)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.view.LayoutInflater.rInflate(LayoutInflater.java:621)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.view.LayoutInflater.inflate(LayoutInflater.java:407)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.view.LayoutInflater.inflate(LayoutInflater.java:320)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
com.ai.ultimap.views.Manual.onItemClick(Manual.java:467)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.widget.AdapterView.performItemClick(AdapterView.java:284)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.widget.AbsListView$PerformClick.run(AbsListView.java:1696)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.os.Handler.handleCallback(Handler.java:587)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.os.Handler.dispatchMessage(Handler.java:92)
12-14 11:43:36.973: E/AndroidRuntime(279):  at android.os.Looper.loop(Looper.java:123)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.app.ActivityThread.main(ActivityThread.java:4627)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
java.lang.reflect.Method.invokeNative(Native Method)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
java.lang.reflect.Method.invoke(Method.java:521)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
12-14 11:43:36.973: E/AndroidRuntime(279):  at dalvik.system.NativeStart.main(Native 
Method)
12-14 11:43:36.973: E/AndroidRuntime(279): Caused by: 
java.lang.reflect.InvocationTargetException
12-14 11:43:36.973: E/AndroidRuntime(279):  at android.widget.ImageView.<init>
(ImageView.java:108)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
java.lang.reflect.Constructor.constructNative(Native Method)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
java.lang.reflect.Constructor.newInstance(Constructor.java:446)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.view.LayoutInflater.createView(LayoutInflater.java:500)
12-14 11:43:36.973: E/AndroidRuntime(279):  ... 18 more
12-14 11:43:36.973: E/AndroidRuntime(279): Caused by: java.lang.OutOfMemoryError: 
bitmap size exceeds VM budget
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.graphics.Bitmap.nativeCreate(Native Method)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.graphics.Bitmap.createBitmap(Bitmap.java:468)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.graphics.Bitmap.createBitmap(Bitmap.java:435)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:488)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:462)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:323)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.content.res.Resources.loadDrawable(Resources.java:1709)
12-14 11:43:36.973: E/AndroidRuntime(279):  at 
android.content.res.TypedArray.getDrawable(TypedArray.java:601)
12-14 11:43:36.973: E/AndroidRuntime(279):  at android.widget.ImageView.<init>
(ImageView.java:118)
12-14 11:43:36.973: E/AndroidRuntime(279):  ... 22 more
12-14 11:43:38.763: I/Process(279): Sending signal. PID: 279 SIG: 9

正如你所看到的,在〜3 MB的位图加载中我特别遇到了一个outofmemory错误…这是没有意义的,因为GC最近运行,没有分配,因为应该使虚拟机在3MB的容量(256 MB).这个256 MB的系统RAM是否只有一小部分实际上是在VM崩溃之前给予的?可能是Bitmap加载过程有自己的内存分配上限吗?
我知道对象池是一个很好的方法来避免游戏循环中的GC,但是不知道什么触发了Dalvik GC,我们仍然对操作系统和Google对性能最佳实践的模糊讨论感到非常信赖.

>可以从代码跟踪GC状态(例如“运行”,“运行”,“完成运行”),以便可以围绕可用内存策略性地计划大量资源分配?我已经看过这个帖子:Determine when the Android GC runs提供了一个有趣的潜在解决方案,但仍然依赖于“伎俩”.我想知道是否有一个支持的API调用,可以在生产代码(而不仅仅是调试)中依赖于跟踪精确状态的垃圾收集器.在某些情况下,System.gc()可能有用,可以检查IF状态;否则,因为它不能承诺立即GC运行,其有用性下降相当多.
> GC总是系统范围内的,还是可以分离线程(如游戏的专用渲染线程),避免GC引起的潜在性能滞后问题?
鉴于以下假设情景:
“我有一个要花费(VM RAM预算)/ 2个字节来实例化的对象,并且我用一个引用立即实例化它.然后,我将该引用清空,使该对象符合GC标准,但当然也不会释放其内存.然后我立即再次实例化对象.
这会使VM崩溃,还是在某种程度上操作系统自动处理这种极端情况,以避免崩溃VM?如果操作系统没有处理它,我会引用它作为一个很好的例子,为什么我上面的问题#2是有效的;如果可以跟踪GC状态,则可以在源中包含逻辑来处理巨大的对象分配问题(实际上比设计糟糕的类更可能是大的资源),通过查看GC加载对象的内存是否在加载之前被释放新的巨大对象实例,并在后台轮询GC时显示小的加载动画.这应该避免应用程序没有响应错误以及合法的内存错误…某种类型的onGC()侦听器将是理想的;可以在本地代码中实现GC监听器,而无需重新构建操作系统内核?

最后,一些源代码…我有正确的想法,以提高性能的Android编程?

活动类别:

package com.ai.ultimap;

//imports omitted...

public class UltiMapActivity extends Activity {
//Housekeeping
private String viewDriverID = "";
private static final int TUTORIAL = 7;

//visuals
private HomeView hv; //home view
private ConfigView cv; //config view
private MapView mv; //map view
private Manual man; //manual view
private int manCount = 0; //tracks the number of times the manual has been called 
    //with menu button,ignoring button presses unless value is zero
private PathCreator pcv; //path creator view
private MasterGL mgl; //the gl center
private String pending = "Coming soon...";
private PathCreator draw;
private Surfacer morlock;
// Used to handle pause and resume...
private static UltiMapActivity master; 

//XML I/O considerations
private String fXML = "mypaths.xml";
private String sXML = "data was not saved properly...?";
private FileOutputStream fos;
private FileInputStream fis;
private FileWriter fw;
private FileReader fr;
private Date theDate = new Date();
private char[] buf = new char[1];

//Feedback stuffs
private FeedbackController Feed;

//tracking you... :)
private WifiStalk stalk;
private long lat;
private long longitude;

//Testing
private DrawView dv;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d("me","ultimap created!");
    master = null;
    mgl = new MasterGL(this); //revisit this later for versatility
    man = new Manual(this);
    Feed = new FeedbackController(this);
    stalk = new WifiStalk(this);
    draw = new PathCreator(this);
    hv = new HomeView(this,draw);
    try {
        BeanCounter bean = new BeanCounter(this);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (XmlPullParserException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    showDialog(TUTORIAL);
}
@Override
public boolean onKeyDown(int keyCode,KeyEvent e){
  if (keyCode == 82){

      if (viewDriverID.equals("hv")){
          hv.removeHV();
      }
      else if (viewDriverID.equals("cv")){
          cv.removeCV();
      }
      else if (viewDriverID.equals("mv")){
         return true;
      }
      else if (viewDriverID.equals("pcv")){
          return true;
      }

      if(man.getAddedState() == 0){

        //Show the manual code...
        System.out.println("View we're coming from: " + this.getVDID());
        Log.e("me","man.getaddedstate does equal 0,should be about to makeMan");

        man.makeMan();      
    }

      else if(man.getAddedState() == 2){ 
        man.removeMan();
        man.removeMan2();
        man.setAddedState(1);
    }
      else if(man.getAddedState() == 1){
        System.out.println("View we're coming from: " + this.getVDID());
        man.addMan();
    }
  }
    return true;
}
@Override
protected Dialog onCreateDialog(int id) {
    //alerts ommitted for space
}

//Used to track the semantic context of what the Activity is displaying
//Getters/setters for external access ommitted

@Override
protected void onStart(){
    super.onStart();
    Log.d("me","ultimap started!");
}
@Override
protected void onPause() {
    super.onPause();
    Log.d("me","ultimap paused!");
    if (mgl.getGLview() != null){
          mgl.getGLview().onPause();
        }
    if (draw.getGLV() != null){
      draw.getGLV().onPause();
    }
}
@Override
protected void onResume() {
    super.onResume();
    Log.d("me","ultimap resumed!");
    stalk.killListener();
    if (mgl.getGLview() != null){

          mgl.getGLview().onResume();
          Log.d("me","mgl.getGLview is NOT null on resume");
        }
    else if (mgl.getGLview() == null){
        mgl.initGL();
        mgl.getGLview().onResume();
        Log.d("me","mgl.getGLview is null on resume");
    }
    if (draw.getGLV() != null){
      draw.getGLV().onResume();
      Log.d("me","draw.getGLV is NOT null on resume");
    }
    else if (draw.getGLV() == null && draw.getHGL() != null){
          draw.pcvInit();
          Log.d("me","draw.getGLV is null on resume");
    }
    if (hv.getMV() != null && hv.getMV().getGLV() != null){
          hv.getMV().getGLV().onResume();
          Log.d("me","map.getGLV is NOT null on resume");
        }
        else if (hv.getMV() != null && hv.getMV().getGLV() == null && 
hv.getMV().getHGL() != null){
            hv.getMV().mvInit();
              Log.d("me","map.getGLV is null on resume");
        }
}
@Override
protected void onStop() {
    super.onStop();
    //Feed.getSP().release();
    Log.d("me","ultimap stopped!");
}

@Override
protected void onRestart(){
    super.onRestart();
    Log.d("me","ultimap restarted!");
    if (mgl != null){
          mgl.initGL(); 

        }   
}
@Override
protected void onDestroy(){
    super.onDestroy();
    Log.d("me","ultimap destroyed!");
    mgl.disposeTextures();
    if (Feed.getSP() != null && Feed.getSID() != 0 && Feed.getLoaded() == 
true){
      Feed.getSP().unload(Feed.getSID());
      Feed.getSP().release();
    }   
}
}

教程视图管理器类:

/*
* This class defines an in-app manual which is callable/dismissable
* in a non-invasive way... 
* 
* http://www.codeproject.com/KB/android/ViewFlipper_Animation.aspx
*http://developer.android.com/reference/android/widget/  
*ViewFlipper.html#ViewFlipper%28android.content.Context%29
* http://developer.android.com/resources/articles/avoiding-memory-leaks.html
*/
package com.ai.ultimap.views;   
//imports ommitted 
public class Manual extends View implements OnItemClickListener{
private UltiMapActivity hUMA;
private ListView lv1;
private ListAdapter la;
private LayoutInflater mInflater;
private Vector<RowData> data;
private TextView tv;
private RelativeLayout holderRL;
private View v;
private View v2;
private int addedState = 0; //tracks whether or not a view has been instantiated,//and if so whether or not it is the currently visible view 
private int addedState2 = 0;

//Grid View stuff
private GridView helpGrid;

//ViewFlipper stuff
private ViewFlipper vf;
private TextView tutTV;
private String mapTutString = "Map View Tutorial Part: ";
private String pcTutString = "Path Creator Tutorial Part: ";
private String tutType;
private TextView counterTV;
private int partCounter = 1;
private float oldTouchValue = 0.0f;
private boolean searchOk = true;
private ImageView floatingImage;

public Manual(UltiMapActivity hAct){
    super(hAct);
    hUMA = hAct;
    holderRL = new RelativeLayout(hUMA);
    v = new View(hUMA);
    floatingImage = new ImageView(hUMA);
}
//Here we summon and populate the grid view
    public void makeMan(){
      if (addedState == 0){
          Log.e("me","in makeMan");
        mInflater = (LayoutInflater) 
hUMA.getSystemService(Activity.LAYOUT_INFLATER_SERVICE); 
        hUMA.addContentView(holderRL,new 
LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
        v = mInflater.inflate(R.layout.helpgrid,holderRL,false);
        helpGrid = (GridView) v.findViewById(R.id.manGV);
        helpGrid.setAdapter(new ImageAdapter(hUMA));
        hUMA.addContentView(v,LayoutParams.MATCH_PARENT));
        helpGrid.setOnItemClickListener(this);
        addedState = 2;
      }

    }

public void addMan(){
    if (v != null && addedState == 1){
        v.setVisibility(VISIBLE);
        v.bringToFront();
        addedState = 2;
    }
}
public void addMan2(){
    if (v2 != null && addedState2 == 1){
        v2.setVisibility(VISIBLE);
        v2.bringToFront();
        addedState2 = 2;
    }
}
public void removeMan(){
    if (v != null && addedState == 2){
        v.setVisibility(GONE);
        addedState = 1;
        String s = hUMA.getVDID();
        if (s.equals("hv")){
            hUMA.getHome().addHV();
            Log.d("me","add hjomeview called from anual");
            Log.d("me","hv addedstate : " + 
hUMA.getHome().getAddedState());
        }
        else if (s.equals("cv")){
            hUMA.getConfig().addCV();
        }
        else if (s.equals("mv")){
            hUMA.getHome().getMV().mvInit();
        }
        else if (s.equals("pcv")){
            hUMA.getDraw().pcvInit();
        }
    }
}
public void removeMan2(){
    if (v2 != null && addedState2 == 2){
        v2.setVisibility(GONE);
        addedState2 = 1;
        String s = hUMA.getVDID();
        if (s.equals("hv")){
            hUMA.getHome().addHV();
            Log.d("me","add hjomeview called from manual");
            Log.d("me","hv addedstate : " + 
hUMA.getHome().getAddedState());
        }
        else if (s.equals("cv")){
            hUMA.getConfig().addCV();
        }
        else if (s.equals("mv")){
            hUMA.getHome().getMV().mvInit();
        }
        else if (s.equals("pcv")){
            hUMA.getDraw().pcvInit();
        }
    }
}

//addedstate getters and setters ommitted for space

 @Override
    public boolean onTouchEvent(MotionEvent touchevent) {

        switch (touchevent.getAction())
        {
            case MotionEvent.ACTION_DOWN:

            {
                System.out.println("received a touch down at " + touchevent.getX() 
+ "," + touchevent.getY());
                oldTouchValue = touchevent.getX();
                if(this.searchOk==false) return false;
                float currentX = touchevent.getX();
                if (currentX > (vf.getWidth()/2))
                {
                    vf.setInAnimation(AnimationHelper.inFromRightAnimation());
                    vf.setOutAnimation(AnimationHelper.outToLeftAnimation());
                    vf.showNext();
                    if (partCounter <= 3 && partCounter >= 1){
                        partCounter++;
                    }
                    else if (partCounter == 4){
                        partCounter = 1;
                    }
                    else{
                        Log.e("me","partCounter got past 4...");
                    }
                    if(tutType.equals("map")){
                        counterTV.setText(mapTutString + partCounter);
                    }
                    else if(tutType.equals("pc")){
                        counterTV.setText(pcTutString + partCounter);
                    }
                    else{
                        Log.e("me","not getting valid tutType string");
                    }
                }
                if (currentX <= (vf.getWidth()/2))
                {
                    vf.setInAnimation(AnimationHelper.inFromLeftAnimation());
                    vf.setOutAnimation(AnimationHelper.outToRightAnimation());

                    vf.showPrevIoUs();
                    if (partCounter >= 2 && partCounter <= 4){
                        partCounter--;
                    }
                    else if (partCounter == 1){
                        partCounter = 4;
                    }
                    else{
                        Log.e("me","partCounter got below 1...");
                    }
                    if(tutType.equals("map")){
                        counterTV.setText(mapTutString + partCounter);
                    }
                    else if(tutType.equals("pc")){
                        counterTV.setText(pcTutString + partCounter);
                    }
                    else{
                        Log.e("me","not getting valid tutType string");
                    }

                }

                break;
            }
            case MotionEvent.ACTION_UP:
            {
                //nothing to do here
            }
        }
        return false;
    }

public void setUserText(String str){
    tv.setText(str);
}

private class CustomTV extends TextView{

    private String content = "";
    public CustomTV(Context c,String str){
        super(c);
        content = str;
        this.setText(content);
    }
}

/**
 * Data type used for custom adapter. Single item of the adapter.      
 */
private class RowData {
    protected String mItem;
        protected String mDescription;
        RowData(String item,String description){
        mItem = item;
        mDescription = description;             
    }

        @Override
        public String toString() {
                return mItem + " " +  mDescription;
        }
}

private class CustomAdapter extends ArrayAdapter<RowData> {

    public CustomAdapter(Context context,int resource,int textViewResourceId,List<RowData> objects) {
            super(context,resource,textViewResourceId,objects);

    }

    @Override
    public View getView(int position,View convertView,ViewGroup parent) {
            ViewHolder holder = null;

            //widgets displayed by each item in your list
            TextView item = null;
            TextView description = null;

            //data from your adapter
            RowData rowData= getItem(position);


            //we want to reuse already constructed row views...
            if(null == convertView){
                    convertView = mInflater.inflate(R.layout.custom_row,null);
                    holder = new ViewHolder(convertView);
                    convertView.setTag(holder);
            }
            holder = (ViewHolder) convertView.getTag();
            item = holder.getItem();
            item.setText(rowData.mItem);
            description = holder.getDescription();          
            description.setText(rowData.mDescription);
            return convertView;
    }
}

/**
* Wrapper for row data.
*
*/
private class ViewHolder {      
private View mRow;
private TextView description = null;
private TextView item = null;

    public ViewHolder(View row) {
    mRow = row;
    }

    public TextView getDescription() {
            if(null == description){
                    description = (TextView) mRow.findViewById(R.id.cBox);
            }
            return description;
    }

    public TextView getItem() {
            if(null == item){
                    item = (TextView) mRow.findViewById(R.id.cBox2);
            }
            return item;
    }       
}

@Override
public void onItemClick(AdapterView<?> arg0,View arg1,int position,long id) {

v.setVisibility(GONE);
if (addedState2 == 0){
hUMA.addContentView(this,DefineLayoutParams.getParams(DefineLayoutParams.getMM()));   
//this is why the onTouch only starts lsitening at this point
if (position == 0){
v2 = mInflater.inflate(R.layout.flipper,false);
vf = (ViewFlipper) v2.findViewById(R.id.manFlipperVF);
tutTV = (TextView) v2.findViewById(R.id.manDescriptionTV);
counterTV = (TextView) v2.findViewById(R.id.mapviewtutCounterTV);
tutTV.setText("Map View Instructions: ...");
counterTV.setText(mapTutString + partCounter);
tutType = "map";
}
else if (position == 1){
    v2 = mInflater.inflate(R.layout.flipperpc,false);
    vf = (ViewFlipper) v2.findViewById(R.id.manFlipperpcVF);
    tutTV = (TextView) v2.findViewById(R.id.manDescriptionpcTV);
    counterTV = (TextView) v2.findViewById(R.id.manFlipperCounterpcTV);
    tutTV.setText("Path Creator Tutorial:...");
    counterTV.setText(pcTutString + partCounter);
    tutType = "pc"; 
}
addedState2 = 2;
hUMA.addContentView(v2,DefineLayoutParams.getParams(DefineLayoutParams.getWW()));
}
else if(addedState2 == 1){
    v2.setVisibility(VISIBLE);
    addedState2 = 2;
}
}
public String getTutType(){
return tutType;
}
}

教程视图Flipper XML:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" 

>
<ScrollView 
android:id="@+id/manDerscriptionSV"
android:layout_width="match_parent"
android:layout_height="200px"
>
<TextView 
android:id="@+id/manDescriptionTV"
android:text="Coming Soon..."
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</ScrollView>
<TextView 
android:id="@+id/mapviewtutCounterTV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Map View Tutorial Part: "
android:gravity="center"
android:layout_below="@id/manDerscriptionSV"
/>
<ViewFlipper
android:id="@+id/manFlipperVF"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/mapviewtutCounterTV"
>
<ImageView 
    android:id="@+id/mapviewtut1"
    android:src="@drawable/mapviewtutflipper1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    />
<ImageView 
    android:id="@+id/mapviewtut2"
    android:src="@drawable/mapviewtutflipper2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    />
<ImageView 
    android:id="@+id/mapviewtut3"
    android:src="@drawable/mapviewtutflipper3"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    />
<ImageView 
    android:id="@+id/mapviewtut4"
    android:src="@drawable/mapviewtutflipper4"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    />


</ViewFlipper>
</RelativeLayout>

谢谢,
CCJ

解决方法

  1. What exactly triggers GC in Android?

这是SDK开发人员不用担心的内部实现细节.

Other VM implementations I’ve seen usually allow for a certain percentage of system memory to be allocated to an application before their GC receives a signal to run.

我会接受你的话. Java不这样做. JVM不关心存在多少系统内存 – 它最多仅关心其自己的VM的潜在堆大小(例如,-Xmx).

Scanning the following LogCat however seems to show Dalvik GC running at least in part quite often

正确.特别是在较新的Android版本上,GC以自己的线程同时运行,而不是先前采取的停止世界的方法.

This doesn’t make sense to me since GC recently ran and nothing allocated since should have brought the VM within 3MB of capacity (256 MB).

您的VM极不可能拥有256MB的堆空间.根据您的设备,它可能低至16MB.

此外,Android没有压缩GC算法,因此即使可能有3MB以上的可用性,您可能没有连续的3MB块.

这就是为什么要重新利用()您的Bitmap对象或尝试重用它们(例如,BitmapOptions的映射,添加在API级别11中).

此外,您可以使用DDMS创建堆转储和MAT检查它,更准确地确定您的内存在哪里,以及谁持有什么.这在Android 3.0上更好,因为MAT将能够更准确地在这些版本中报告Bitmap内存.

Is there only a small percentage of that 256 MB system RAM which is actually given to the VM before it crashes?

是.它被称为堆. Android设备的堆大小限制.通常情况下,它的范围是16-48MB,具体取决于Android操作系统版本和屏幕分辨率.

Could it be that the Bitmap loading process has its own memory allocation cap?

不,它可以从相同的堆大小预算中起作用.从Android 3.0开始,它真的将与其他Dalvik对象使用的内存一样加载 – 以前,它使用堆外部的系统RAM块,但是这个空间是根据堆的大小预算计算的.

but without knowing EXACTLY what triggers Dalvik GC we’re still placing an awful lot of faith in the OS and Google’s vague discussions of performance best-practices

生活就像他们说的那样继续下去.

Can the GC state (e.g. ‘about to run’,‘running’,‘finished running’) be tracked from code so that large resource allocations might be planned strategically around available memory? … I’d like to know if there is a supported API call somewhere which can be relied upon in production code (not just debug) to track the precise state of the garbage collector.

没有.

Is GC always system-wide,or can separate threads (such as a dedicated rendering thread for a game) escape the potential performance lag issues caused by GC?

GC对于任何虚拟机来说都不是“系统范围”. GC始终位于VM内.

在较新的Android版本中,GC是并发的,因此在正常情况下不会实质阻止任何线程.在旧版本的Android上,GC是世界上的一切,将影响所有的线程. Android 3.0的变化肯定是适用的 – 对于并发GC是否已经适用于Android 2.3,我的记忆是模糊的.有一个2011年Google I | O的Android内存管理演示文稿,您可能希望观看.

Would this crash the VM or is there some way the OS handles such extreme situations automatically to avoid crashing the VM?

升级OutOfMemoryException之前,Android应强制立即使用GC.这种情况符合我以前的副标题不是“正常情况”.

猜你在找的Java相关文章