gpt4 book ai didi

java - Android GC 考虑因素——GC 何时运行,是否可以从代码中跟踪其运行状态?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:21:13 24 4
gpt4 key购买 nike

我一直在寻找描述 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 位图加载期间特别遇到内存不足错误...这对我来说没有意义,因为 GC 最近运行并且没有分配任何东西,因为应该将 VM 带入 3MB 以内容量(256 MB)。 256 MB 系统 RAM 中是否只有一小部分在崩溃前实际分配给了 VM?难道是Bitmap加载过程有自己的内存分配上限?我知道对象池是在游戏循环期间尝试避免 GC 的好方法,但是在不知道究竟是什么触发了 Dalvik GC 的情况下,我们仍然对操作系统和 Google 对性能最佳实践的模糊讨论抱有极大的信心。

  1. 能否从代码中跟踪 GC 状态(例如“即将运行”、“正在运行”、“已完成运行”),以便围绕可用内存有策略地规划大量资源分配?我已经阅读了这篇关于此事的帖子:Determine when the Android GC runs它提供了一个有趣的潜在解决方案,但仍然依赖于“技巧”。我想知道在生产代码(不仅仅是调试)中是否可以依赖某个受支持的 API 调用来跟踪垃圾收集器的精确状态。如果可以检查 GC 状态,System.gc() 在某些情况下可能会有用;否则,由于它不能保证立即运行 GC,因此它的实用性会下降很多。

  2. GC 是否始终在系统范围内进行,或者单独的线程(例如游戏的专用渲染线程)是否可以避免 GC 导致的潜在性能延迟问题?

  3. 给定以下假设场景:'我有一个实例化成本为(VM RAM 预算)/2 字节的对象,我立即使用单个引用实例化它。然后我取消该引用,使该对象符合 GC 的条件,但当然还没有真正释放它的内存。然后我立即再次实例化该对象。这会导致 VM 崩溃吗?或者操作系统是否有某种方式自动处理这种极端情况以避免 VM 崩溃?如果操作系统不处理它,我会引用它作为一个很好的例子来说明为什么我上面的问题 #2 是有效的;如果可以跟踪 GC 状态,则可以在源代码中包含逻辑来处理巨大的对象分配问题(实际上更可能是大型资源而不是设计糟糕的类),方法是检查加载之前是否释放了符合 GC 条件的对象的内存新的巨大对象实例,并在后台轮询 GC 时显示一个小的加载动画。这应该避免应用程序不响应错误以及合法的内存不足错误......某种 onGC() 监听器将是理想的;是否可以在不重新构建操作系统内核的情况下以 native 代码实现 GC 监听器?

5.最后,一些源代码...我对高效的 Android 编程有正确的想法吗?

Activity 类:

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

教程 View 管理器类:

/*
* 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, new
LayoutParams(LayoutParams.MATCH_PARENT,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, holderRL, 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, holderRL, 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;
}
}

教程 View 翻转器 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 block 。

这就是为什么 recycle() 您的 Bitmap 对象或尝试重用它们(例如,inBitmap)很重要>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 block ,但空间被计入堆的大小预算。

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?

对于任何 VM,GC 都不是“系统范围的”。 GC 始终在 VM 内。

在较新版本的 Android 上,GC 是并发的,因此在正常情况下不会实质性地阻塞任何线程。在旧版本的 Android 上,GC 是 stop-the-world 并且会影响所有线程。 Android 3.0 确实发生了变化——我对并发 GC 是否已经在 Android 2.3 上发生了模糊的内存。您可能希望观看有关 Android 内存管理的 2011 年 Google I|O 演示。

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

Android 应该在引发 OutOfMemoryException 之前强制立即进行 GC。根据我之前的段落,这种情况不属于“正常情况”。

关于java - Android GC 考虑因素——GC 何时运行,是否可以从代码中跟踪其运行状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8509886/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com