我现在一直在寻找一些描述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 – Android GC注意事项 – GC何时运行,并可以从代码跟踪其运行状态?的更多相关文章

  1. android – 错误膨胀FloatingActionButton的布局:NoSuchMethodException

    所以我在布局时出现了错误,这是关于NoSuchMethodException的.我已经看过其他解决方案,我已经确定我已经完成了以下操作,我已经完成了这个例外.有谁知道这可能导致什么?我完全迷失了,一切正常,然后我更新了我的android工作室,现在我收到了这个错误.我的活动是AppCompatActivity我的应用布局,使用AppCompat:我的布局代码,使用app命名空间设置背景色调:这是我

  2. 无法使用android.support.v7.widget.AppCompatTextView实例化以下类

    最近我在Android工作室的应用程序中将我的sdk从25改为26,我在我的所有xml中都遇到了这个奇怪的错误.目前错误并没有以我能看到的任何方式影响我的应用程序,但是每次我必须编辑或更改xml中的某些内容时都很烦人.这里的错误:无法实例化以下类–android.support.v7.widget.AppCompatTextView我的朋友:编辑:添加了一些我的xml代码解决方法我也收到了这个错误

  3. android – LayoutInflater有时(随机)膨胀错误的背景颜色

    我使用LayoutInflater扩展视图.我的膨胀RelativeLayout的背景颜色在我的xml文件中设置.我在我的一个设备上遇到了一个奇怪的问题:有时(随机)背景颜色是我的colors.xml中的另一种(错误的)颜色.以前有人遇到过这个问题吗?

  4. android – 在运行时创建,存储和膨胀自定义布局

    我正在尝试找到解决以下问题的方法.我工作的应用程序要求用户通过自定义UI构建器生成自定义UI.因此,用户可以在画布上堆叠小部件,移动它们等等.UI必须存储在数据库中以备将来使用.因此,应该有一些加载和膨胀此UI的机制.这是主要问题.我的第一个想法是依靠标准的Android布局机制.不幸的是,LayoutInflater使用XML编译成二进制形式.据我所知,在运行时将XML字符串编译成二进制表示是不可能的.有没有人遇到过这样的问题?

  5. android-5.0-lollipop – 如何修复’你必须在include标签中指定一个布局:’

    我在Android工作室使用材料设计为前棒棒糖设备创建一个Android应用程序,我是android工作室的新手我正在我的项目中创建一个工具栏但我收到一个错误名为“引起:android.view.InflateException:你必须在include标签中指定一个布局:“请帮我解决这个问题,这是我的活动代码:这是我的xml:这是我的工具栏Xml:解决方法我找到了自己问题的答案.在我的工具acti

  6. Android Studio 1.2.1.1布局预览问题

    更新到AndroidStudio1.2.1.1后,我创建了一个新的空白项目并创建了一个layout.xml创作后不久,我决定查看预览.我进去了,我看到了这个:ThefollowingclassesCouldnotbeinstantiated:–android.support.v7.internal.widget.ActionBarOverlayLayout(OpenClass,ShowExcept

  7. android – 错误膨胀类ImageView

    我间歇性地得到了InflateException/ClassNotFoundException错误.我之前在SO中看到过类似的错误但它们是由拼写错误引起的.我正确地拼写了’ImageView’所以我不知道是什么导致了错误.发生错误的代码是:这是布局xml:这是错误日志:解决方法试着改变至

  8. android – 无法呈现Google SignInButton

    使用Google登录按钮:解决方法我相信这是最新的GooglePlayServices(5.0)代码中的错误和/或与gradle和AndroidStudio的集成.我遇到了同样的问题,我通过降级项目中使用的GooglePlay服务版本来解决这个问题.我在依赖项部分下的build.gradle中添加了以下内容:之后,错误消失了,布局设计师能够在屏幕上呈现Google登录按钮.

  9. android – 实现扩展/自定义View为构造函数抛出NoSuchMethod

    我有一个自定义的TextView,它实现了三个View构造函数:这是一个非静态内部类,因为它需要从外部类访问实例数据.它出现在.xml布局中:一切都编译和安装很好,但在运行时:在我看来,这意味着它无法找到构造函数的版本……有没有办法进一步调试?

  10. android – 使用自定义textSize实现自定义TextView

    我已经实现了自定义TextView,然后我需要更改其文本大小以供将来使用.在那一步,我决定使用style.xml和attr.xml进行textSize自定义但是,当我的自定义布局膨胀时,我收到运行时错误.与我为了自定义而更改的部件相关的错误.这是我实现的代码片段.attr.xmlstyles.xmllayout_field_detailed.xmllayout_implementation.xml

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部