我读过一些关于在android中释放内存的内容,但我仍然对这种行为感到困惑。在我的情况下,我测试一个简单的应用程序,分配内存和何时释放。我有两个活动。在MainActivity中,我有一个ImageView。我通过getResources().getDrawable(int id)
或BitmapFactory.decodeResource(Resources res, int id)
引用了可绘制的图片。两种方式都可以确保为图像分配内存,但即使我破坏了我的活动,回收位图或将所有变量设置为null,这个内存也不会被释放。
public class MainActivity extends Activity {
private ImageView view;
private Drawable drawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = (ImageView) findViewById(R.id.image);
// tried with BitmapFactory.decode...
drawable = getResources().getDrawable(R.drawable.connect);
view.setImageDrawable(dr);
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(),
SecondActivity.class);
startActivity(intent);
// tried with and without finish
finish();
}
});
}
@Override
protected void onResume() {
super.onResume();
Double allocated = new Double(Debug.getNativeHeapAllocatedSize())
/ new Double((1048576));
Double available = new Double(Debug.getNativeHeapSize()) / 1048576.0;
Double free = new Double(Debug.getNativeHeapFreeSize()) / 1048576.0;
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setMinimumFractionDigits(2);
System.out.println("SYSO : " + df.format(allocated) + "MB of "
+ df.format(available) + "MB (" + df.format(free) + "MB free)");
System.out.println("SYSO : "
+ df.format(new Double(
Runtime.getRuntime().totalMemory() / 1048576))
+ "MB of "
+ df.format(new Double(
Runtime.getRuntime().maxMemory() / 1048576))
+ "MB ("
+ df.format(new Double(
Runtime.getRuntime().freeMemory() / 1048576))
+ "MB free)");
}
@Override
protected void onDestroy() {
super.onDestroy();
// tried using BitmapFactory and bitmap.recycle()
dr.setCallback(null);
dr = null;
view = null;
System.gc();
Runtime.getRuntime().gc();
}
}
我也在第二次活动中记录内存。我发现,我的应用程序在启动时有大约8-9MB的运行时内存。在主视图中分配我的图像,让内存增长到大约20MB。当我使用finish()
离开我的活动并使用所有释放的东西,比如设置回调null和回收图像时,为什么第二个活动中的内存仍然被分配?我正在多次恢复第二个活动并且仍然分配了内存。我的第一个活动被破坏了,我怎么能释放它的记忆?我在没有设置callback = null
或回收位图并完成MainActivity
的情况下测试了行为。然后,每次我恢复MainActivity
时,每个简历的内存增长大约10MB。听起来不错,因为旧的引用不会被销毁,每次都会分配新的图像。但是为什么第一张图像的初始记忆不会被破坏?
答案 0 :(得分:1)
我认为你有内存泄漏,首先在谷歌I / O 2011上关于内存管理观看这个非常好的视频 - > http://www.youtube.com/watch?v=_CruQY55HOk然后在了解垃圾收集后你可以尝试使用eclipse MAT(Memory Analyzer Tool)来查找内存泄漏http://www.eclipse.org/mat/
对于位图,我建议您重复使用位图将其缓存在内存中。您可以像这样实现它:
public class MemoryCache {
String TAG = "MemoryCache";
private Map<String, Bitmap> cache=Collections.synchronizedMap(
new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering
private long size=0;//current allocated size
private long limit=1000000;//max memory in bytes
public MemoryCache(){
//use 25% of available heap size
setLimit(Runtime.getRuntime().maxMemory()/4);
}
public void setLimit(long new_limit){
limit=new_limit;
}
public Bitmap get(String id){
try{
if(!cache.containsKey(id))
return null;
//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
return cache.get(id);
}catch(NullPointerException ex){
return null;
}
}
public void put(String id, Bitmap bitmap){
try{
if(cache.containsKey(id))
size-=getSizeInBytes(cache.get(id));
cache.put(id, bitmap);
size+=getSizeInBytes(bitmap);
checkSize();
}catch(Throwable th){
th.printStackTrace();
}
}
private void checkSize() {
if(size>limit){
Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated
while(iter.hasNext()){
Entry<String, Bitmap> entry=iter.next();
size-=getSizeInBytes(entry.getValue());
iter.remove();
if(size<=limit)
break;
}
}
}
public void clear() {
cache.clear();
}
long getSizeInBytes(Bitmap bitmap) {
if(bitmap==null)
return 0;
return bitmap.getRowBytes() * bitmap.getHeight();
}
}
并将其存储为:
memoryCache.put(photoToLoad.url, bmp);
并检查你的情况下的url或URI或drawable名称是否在创建新位图之前存在于缓存中
WeakReference<Bitmap> bitmap = new WeakReference<Bitmap>(
memoryCache.get(url));
我假设您知道如何修改我的代码以存储来自drawable或URI的缓存,但如果您对我的答案有疑问,请随时在评论中询问,如果您发现我的答案有用,请不要忘记投票和接受所以其他人也可以阅读这个:)
答案 1 :(得分:1)
在这里您可以看到MAT的直方图视图。我完成了MainActivity并启动了SecondActivity。但FinalizerReference仍然持有MainActivity。为什么呢?