image - 同时将图像加载到Bitmap对象内存不足问题

  显示原文与译文双语对照的内容

我有一个列表视图,每一行有一对图像按钮。 当你单击列表行时,它会启动一个新的Activity 。 由于相机布局问题,我不得不创建自己的标签。 为结果启动的Activity 是一个映射。 如果点击了我的按钮以启动图像预览( 从SD卡上加载图像) 应用程序返回从 Activity 到 listview Activity 到要重新开始我新的Activity,没什么比图像小部件的结果处理程序。

列表视图上的图像预览正在使用光标和 ListAdapter 完成。 这使得它非常简单,但我不知道如何放置大小调整的图像( 例如 。 较小的位大小不是图像按钮上的src像素。 我刚调整了手机上的图像。

这个问题是这样我得到了一个内存不足错误如果将尝试返回并在 2 re-launch Activity 上述作品。

动态地 ** 那有什么方法可以构建该列表适配器方便地逐行,在那里我可以调整? 这将是可取的,因为我还需要对每一行中的小部件/元素的属性进行一些更改,因为我不能因为焦点问题而选择一个触摸屏。 ( 我可以使用 roller 。)

** 我知道我可以做一个乐队大小的调整和保存我的图像,但这不是我想要做的,但是一些示例代码是不错的。

一旦我禁用了列表视图上的图像,它就可以正常工作了。

注意:这就是我如何做到的:


String[] from = new String[] { DBHelper.KEY_BUSINESSNAME,
 DBHelper.KEY_ADDRESS,
 DBHelper.KEY_CITY,
 DBHelper.KEY_GPSLONG,
 DBHelper.KEY_GPSLAT,
 DBHelper.KEY_IMAGEFILENAME +""};
int[] to = new int[] { R.id.businessname,
 R.id.address,
 R.id.city,
 R.id.gpslong,
 R.id.gpslat,
 R.id.imagefilename };
notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);

R.id.imagefilename 是一个 ButtonImage

下面是我的试用版:



01-25 05:05:49.877: ERROR/dalvikvm-heap(3896): 6291456-byte external allocation too large for this process.
01-25 05:05:49.877: ERROR/(3896): VM wont let us allocate 6291456 bytes
01-25 05:05:49.877: ERROR/AndroidRuntime(3896): Uncaught handler: thread main exiting due to uncaught exception
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:149)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:174)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.drawable.Drawable.createFromPath(Drawable.java:729)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ImageView.resolveUri(ImageView.java:484)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ImageView.setImageURI(ImageView.java:281)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:183)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:129)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.CursorAdapter.getView(CursorAdapter.java:150)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.AbsListView.obtainView(AbsListView.java:1057)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.makeAndAddView(ListView.java:1616)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.fillSpecific(ListView.java:1177)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.layoutChildren(ListView.java:1454)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.AbsListView.onLayout(AbsListView.java:937)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.onLayout(LinearLayout.java:922)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:999)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.onLayout(LinearLayout.java:920)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.ViewRoot.performTraversals(ViewRoot.java:771)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.ViewRoot.handleMessage(ViewRoot.java:1103)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.os.Handler.dispatchMessage(Handler.java:88)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.os.Looper.loop(Looper.java:123)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.app.ActivityThread.main(ActivityThread.java:3742)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at java.lang.reflect.Method.invokeNative(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at java.lang.reflect.Method.invoke(Method.java:515)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at dalvik.system.NativeStart.main(Native Method)
01-25 05:10:01.127: ERROR/AndroidRuntime(3943): ERROR: thread attach failed


在显示图像时,我也有一个新错误:


01-25 22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d
01-25 22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri: 
01-25 22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process.
01-25 22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes
01-25 22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed

时间:

Android训练类"有效地显示位图"提供了一些理解和处理异常的重要信息java.lang.OutOfMemoryError: bitmap size exceeds VM budget 加载位图时。

要修复OutOfMemory错误,应该执行如下操作:


BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap = BitmapFactory.decodeStream(is, null, options);

这里 inSampleSize 选项减少内存消耗。

这是一个完整的方法。首先它读取图像大小而不解码内容本身。 然后找到最好的inSampleSize 值,它应该是 2的幂,最后将图像解码。


//Decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
 try {
//Decode image size
 BitmapFactory.Options o = new BitmapFactory.Options();
 o.inJustDecodeBounds = true;
 BitmapFactory.decodeStream(new FileInputStream(f), null, o);

//The new size we want to scale to
 final int REQUIRED_SIZE=70;

//Find the correct scale value. It should be the power of 2.
 int scale = 1;
 while(o.outWidth/scale/2> = REQUIRED_SIZE && 
 o.outHeight/scale/2> = REQUIRED_SIZE) {
 scale *= 2;
 }

//Decode with inSampleSize
 BitmapFactory.Options o2 = new BitmapFactory.Options();
 o2.inSampleSize = scale;
 return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
 } catch (FileNotFoundException e) {}
 return null;
}

我对Fedor的代码做了一个小小的改进。 在一个two,它基本上是使用相同,但没有( 在我看来) 难看;而循环的功能,而且它总能 results. 对Fedor做出的原始解决方案的荣誉,我一直坚持,直到找到他,然后我才能做到这一点:


 private Bitmap decodeFile(File f){
 Bitmap b = null;

//Decode image size
 BitmapFactory.Options o = new BitmapFactory.Options();
 o.inJustDecodeBounds = true;

 FileInputStream fis = new FileInputStream(f);
 BitmapFactory.decodeStream(fis, null, o);
 fis.close();

 int scale = 1;
 if (o.outHeight> IMAGE_MAX_SIZE || o.outWidth> IMAGE_MAX_SIZE) {
 scale = (int)Math.pow(2, (int) Math.ceil(Math.log(IMAGE_MAX_SIZE/
 (double) Math.max(o.outHeight, o.outWidth))/Math.log(0.5)));
 }

//Decode with inSampleSize
 BitmapFactory.Options o2 = new BitmapFactory.Options();
 o2.inSampleSize = scale;
 fis = new FileInputStream(f);
 b = BitmapFactory.decodeStream(fis, null, o2);
 fis.close();

 return b;
}

我来自iOS的经验,我很沮丧地发现了这么简单的问题,比如加载和显示图像。 毕竟,这个问题的每个人都在试图显示合理大小的图像。 不管怎样,这是我解决问题的两个修改( 让我的应用非常有React) 。

1 ) 每次执行 BitmapFactory.decodeXYZ() 时,一定要将一个带有 inPurgeable 设置的BitmapFactory.Options 传递给 true ( 并且最好使用 inInputShareable 同时设置为 true ) 。

2 ) 从不使用 Bitmap.createBitmap(width, height, Config.ARGB_8888) 经过几个 passes, 。我是说不错过任何我有毕业时不会引发内存错误。 没有多少 recycle()System.gc(),任何帮助。 总是引发异常。一个其他的方式,它的面膜是让一个虚拟的图像在你的图像( 或者使用上面的步骤 1解码的另一个位图) 一致,重新缩放到任何你想要的,然后操纵已经生成的位图( 比如将它传递到画布以获得更多乐趣) 。 所以,你应该使用的是: Bitmap.createScaledBitmap(srcBitmap, width, height, false) 如果你必须使用蛮力创建方法,那么至少通过 Config.ARGB_4444

这几乎可以保证你在没有天数的情况下节省你的时间。 所有关于缩放图像的讨论,等等 并不是真正的工作。

但是,谷歌,认真?

它是一个已知的Bug,不是因为大文件。 由于Android缓存了图像,所以在使用很少的图像后内存就会用尽。 但是我找到了另一种方法,跳过android默认缓存系统。

解决方案: 将图像移动到"assets"文件夹并使用以下函数获取 BitmapDrawable:


public static Drawable getAssetImage(Context context, String filename) throws IOException {
 AssetManager assets = context.getResources().getAssets();
 InputStream buffer = new BufferedInputStream((assets.open("drawable/" + filename +".png")));
 Bitmap bitmap = BitmapFactory.decodeStream(buffer);
 return new BitmapDrawable(context.getResources(), bitmap);
}

我有同样的问题,通过避免 BitmapFactory.decodeStream 或者decodeFile函数,而改用 BitmapFactory.decodeFileDescriptor

decodeFileDescriptor 看起来与 decodeStream/decodeFile调用的原生方法不同。

不管怎样,哪些有效是这样( 注意,我添加了一些选项上面就像一些人,但那不是有何差别。 什么是关键是调用了 BitmapFactory.decodeFileDescriptor 代替 decodeStream 或者 decodeFile ):


private void showImage(String path) {
 Log.i("showImage","loading:"+path);
 BitmapFactory.Options bfOptions=new BitmapFactory.Options();
 bfOptions.inDither=false;//Disable Dithering mode
 bfOptions.inPurgeable=true;//Tell to gc that whether it needs free memory, the Bitmap can be cleared
 bfOptions.inInputShareable=true;//Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
 bfOptions.inTempStorage=new byte[32 * 1024]; 


 File file=new File(path);
 FileInputStream fs=null;
 try {
 fs = new FileInputStream(file);
 } catch (FileNotFoundException e) {
//TODO do something intelligent
 e.printStackTrace();
 }

 try {
 if(fs!=null) bm=BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions);
 } catch (IOException e) {
//TODO do something intelligent
 e.printStackTrace();
 } finally{ 
 if(fs!=null) {
 try {
 fs.close();
 } catch (IOException e) {
//TODO Auto-generated catch block
 e.printStackTrace();
 }
 }
 }
//bm=BitmapFactory.decodeFile(path, bfOptions); This one causes error: java.lang.OutOfMemoryError: bitmap size exceeds VM budget

 im.setImageBitmap(bm);
//bm.recycle();
 bm=null;



}

我认为 decodeStream/decodeFile中使用的本机函数有问题。 我已经确认在使用decodeFileDescriptor时调用了一个不同的本机方法。 也就看过的内容评"图像( 位图) ) 是不会以一个标准的Java的方式,但通过本机调用;分配给拨款都要的虚拟堆,无关,而是针对它计算在内 ! "

我认为避免 OutOfMemoryError的最好方法是面对它并理解它。

我使应用程序故意导致 OutOfMemoryError,并监视内存使用情况。

在使用这个应用进行了大量的实验之后,我得到了以下结论:

我将在第一次使用Honey之前讨论SDK版本。

  1. 位图存储在原生堆中,但它会自动收集垃圾,调用 recycle() 是不必要的。

  2. 如果本机堆 {VM 堆 size} + {allocated memory}> = {VM 堆大小限制对于 device},而且你正在尝试创建位图,会抛出 OOM 。

    注意:虚拟机堆大小计数而不是虚拟机分配的内存。

  3. 即使已经分配的VM内存正在收缩,VM堆大小也不会收缩。

  4. 因此,你必须保持峰值虚拟机内存尽可能的低,以防止虚拟机堆大小增长太大,从而节省位图的可用内存。

  5. 手动调用 System.gc() 是无意义的,系统会在尝试增长堆大小之前先调用它。

  6. 本机堆大小不能收缩太,但它是为OOM不计酬,因此不需要再担心了。

那么,我们来谈谈从Honey开始的SDK 。

  1. 位图存储在虚拟机堆中,本机内存不会被计算为 OOM 。

  2. 条件更简单: {VM 堆 size}> = {VM的堆大小限制。

  3. 因此,你有更多可用的内存来创建具有相同堆大小限制的位图,而不可能引发。

下面是一些关于垃圾收集和内存泄漏的观察。

你可以在应用中看到它。 如果 Activity 执行了一个在 Activity 被销毁后仍在运行的AsyncTask,Activity 将不会得到垃圾收集,直到最终用户完成。

这是因为AsyncTask是匿名内部类的一个实例,它持有 Activity的引用。

如果在后台线程中的IO操作中阻塞任务,调用 AsyncTask.cancel(true) 不会停止执行。

回调是匿名内部类,因此如果项目中的静态实例持有它们并且不释放它们,则会泄漏内存。

在 onPause(), 内存就可以leaked,如果你预定一个重复或者延迟任务,例如一个定时器,要是没有线索 cancel() 和

最近,我看到了许多关于linux异常和缓存的问题。 在一个合适的开发指导有 way,一个真正的好文章在这里,但有些倾向于失败关于实现管它,

由于这个原因,我编写了一个示例应用程序,它演示了在Android环境中缓存。 这里实现还没有得到一个。

查看这里答案的结尾以获得源代码的链接。

需求:

  • Androidapi 2.1或者更高( 我不可能简单设法得到可用的内存为应用程序在 API 1.6 -,同样也是唯一的代码部分,不在 API 1.6 )
  • Android支持软件包

Screenshot

功能:

  • 使用的是 singleton, 保留了缓存如果有一个方向更改,
  • 使用八分之一指派的应用程序的内存到缓存中( 如果你希望修改)
  • 大位图获取缩放 ( 你可以定义所需的最大像素为允许)
  • 在下载位图之前,控制有互联网连接可用的 。
  • 将确保你是只实例化一个任务每行
  • 如果在 ListView 你是投掷掉之间,那是绝对不是下载位图

这不包括:

  • disk,处的磁盘缓存。所以可以很方便地实现- 只指向一个不同的任务,获取位图

代码示例:

正在下载的图像是来自Flickr的图像( 75 x75 ) 。 然而,放任何图像url要被处理,并且该应用程序将它的体积缩小在超出最大。 在这个应用程序中,url只是在一个 String 数组中。

LruCache 有一个处理位图的好方法。 但是,在这个应用程序中我把一个实例中创建的一个类,它的另一个盒子内 LruCache 我的订单,以便将应用程序更加的灵活。

缓存的关键。java内容( loadBitmap() 方法是最重要的):


public Cache(int size, int maxWidth, int maxHeight) {
//Into the constructor you add the maximum pixels
//that you want to allow in order to not scale images.
 mMaxWidth = maxWidth;
 mMaxHeight = maxHeight;

 mBitmapCache = new LruCache<String, Bitmap>(size) {
 protected int sizeOf(String key, Bitmap b) {
//Assuming that one pixel contains four bytes.
 return b.getHeight() * b.getWidth() * 4;
 }
 };

 mCurrentTasks = new ArrayList<String>(); 
}

/**
 * Gets a bitmap from cache. 
 * If it is not in cache, this method will:
 * 
 * 1: check if the bitmap url is currently being processed in the
 * BitmapLoaderTask and cancel if it is already in a task (a control to see
 * if it's inside the currentTasks list).
 * 
 * 2: check if an internet connection is available and continue if so.
 * 
 * 3: download the bitmap, scale the bitmap if necessary and put it into
 * the memory cache.
 * 
 * 4: Remove the bitmap url from the currentTasks list.
 * 
 * 5: Notify the ListAdapter.
 * 
 * @param mainActivity - Reference to activity object, in order to
 * call notifyDataSetChanged() on the ListAdapter.
 * @param imageKey - The bitmap url (will be the key).
 * @param imageView - The ImageView that should get an
 * available bitmap or a placeholder image.
 * @param isScrolling - If set to true, we skip executing more tasks since
 * the user probably has flinged away the view.
 */
public void loadBitmap(MainActivity mainActivity, 
 String imageKey, ImageView imageView,
 boolean isScrolling) {
 final Bitmap bitmap = getBitmapFromCache(imageKey); 

 if (bitmap!= null) {
 imageView.setImageBitmap(bitmap);
 } else {
 imageView.setImageResource(R.drawable.ic_launcher);
 if (!isScrolling &&!mCurrentTasks.contains(imageKey) && 
 mainActivity.internetIsAvailable()) {
 BitmapLoaderTask task = new BitmapLoaderTask(imageKey,
 mainActivity.getAdapter());
 task.execute();
 }
 } 
}

你不需要在 Cache.java 文件中编辑任何内容,除非你想实现磁盘缓存。

MainActivity.java的关键:


public void onScrollStateChanged(AbsListView view, int scrollState) {
 if (view.getId() == android.R.id.list) {
//Set scrolling to true only if the user has flinged the 
//ListView away, hence we skip downloading a series
//of unnecessary bitmaps that the user probably
//just want to skip anyways. If we scroll slowly it
//will still download bitmaps - that means
//that the application won't wait for the user
//to lift its finger off the screen in order to
//download.
 if (scrollState == SCROLL_STATE_FLING) {
 mIsScrolling = true;
 } else {
 mIsScrolling = false;
 mListAdapter.notifyDataSetChanged();
 }
 } 
}

//Inside ListAdapter...
@Override
public View getView(final int position, View convertView, ViewGroup parent) { 
 View row = convertView;
 final ViewHolder holder;

 if (row == null) {
 LayoutInflater inflater = getLayoutInflater();
 row = inflater.inflate(R.layout.main_listview_row, parent, false); 
 holder = new ViewHolder(row);
 row.setTag(holder);
 } else {
 holder = (ViewHolder) row.getTag();
 } 

 final Row rowObject = getItem(position);

//Look at the loadBitmap() method description...
 holder.mTextView.setText(rowObject.mText); 
 mCache.loadBitmap(MainActivity.this,
 rowObject.mBitmapUrl, holder.mImageView,
 mIsScrolling); 

 return row;
}

getView() 经常被调用。 它通常不是一个好主意来下载图片在那里,如果我们还没有实现了一个检测,确保我们每行,我们不会开始一个无限数量的线程。 Cache.java 检查 rowObject.mBitmapUrl 是否已经在任务中,如果是,它将不会启动另一个。 因此,我们很可能不会超过 AsyncTask 池的工作队列限制。

下载:

你可以从 https://www.dropbox.com/s/pvr9zyl811tfeem/ListViewImageCache.zip 编辑器下载源代码。


最后一句话:

我有测试过现在过几周后,我没有接到命令还单个OOM异常。 我在 模拟器,Nexus 和 Nexus 上测试了这个。 我已经测试了包含高清质量图像的图像 url 。 唯一的瓶颈是下载更多的时间。

只有一种可能的场景,我可以想象到,会出现 OOM,这就是如果我们下载各类的,真正的大图像,并且在失控之前将规定和放入缓存,将同时占用更多的内存,从而发生 OOM 。 以一种更可行way,甚至但这不是理想的环境中无论如何,它很有可能将不能够 solve.

在评论中报告错误 ! :- )

你很可能遭受了这个 Android Bug

Bug 报告包含一个测试用例。

这似乎是一个长期运行的问题,有很多不同的解释。 我把我们的建议在这里提出应用该两种最常见的答案,然而这两者其中一个解决自己的毛病不输出到屏幕要求它的在字节为单位来执行解码承受不起必要的过程。 位于本机 heap,挖掘了我了解到这里的真正的问题是这个解码过程的执行情况后拿走了。

看这里:BitmapFactory OOM驱动我的

这将我引向另一个讨论线程,在那里我发现了更多关于这个问题的解决方案。 一个是在显示图像后手动调用 System.gc(); 。 但这实际上使你的应用程序使用更多的内存,以减少原生堆。 发布 2.0 ( Donut )的更好解决方案是使用BitmapFactory选项"inPurgeable"。 然后所以我持续添加 o2.inPurgeable=true; just.

有关这里主题的更多信息: 是内存堆的限制仅 6 M

现在,我已经说过了,我是一个完全有Java和安卓的傻瓜。 所以如果你认为这是解决这个问题的糟糕方法,你可能是正确的。 ;- ) 但是我们一定对我来说工作奇妙,而我却在不可能现在来运行虚拟机移出堆栈缓存。 我发现的唯一缺点是你正在废弃你的缓存的镜像图像。 这意味着如果你回到那个图像,你每次都会重画它。 在我的应用程序如何工作的情况下,这并不是真正的问题。 您的情况可能会有所不同。

...