内存泄漏分析(二)
上一篇说过,我的项目很特殊,就是只有一个页面,定时从服务器获取数据,并显示界面。因为业务的保密性,不好直接贴图。
看着很简单的一个界面,运行内存是这样的
最少的也是100M左右。等到跳到200多M的时候,离崩溃已经不远了。我就让程序这样运行,看着下面跳到的线。我采取了最原始的方式。屏蔽代码,只留最简单的网络访问。经过观察我发现问题
网络访问我用的是retrofit,访问完成的结果是个json字符串。
就是这样的一个变量定义与赋值,造成了短时间内的内存猛增。
再看这样一些傻傻的类。这些变量是成员变量
局部变量,存放在栈空间中,书写在方法或语句块中。语句块一结束,变量空间马上释放。所以,局部变量不能跨方法或语句块使用。
成员变量(属性):存放在堆中,书写在方法外,类中。随对象产生而产生,随对象销毁而消失。
我最初的想法是这些变量写在类里,每15s获取一次,也不用创建很多次,并且每次赋值前,我都置空了的。事实胜于雄辩,当我把这些变量全部改为局部变量以后,内存变化如下:
接下来我先加了底部的几个自定义的控件,没有太大的变化。最后加了地图。地图那块本来是有很多图标的,我把图标交给了Picasso 的框架去管理。
写法如下:附上整个MapUtils的类
public class MapUtils { public static final int STYPE_SHOW_MENDIAN = 0; public static final int STYPE_SHOW_DINGDAN = 1; public static final int STYPE_SHOW_QISHOU = 2; private static List<BitmapDescriptor> mOptionList = new ArrayList<>(); private static List<Marker> markerList = new ArrayList<>(); private static ArrayList<MarkerOptions> makergroup = new ArrayList<>(); private static List<View> views = new ArrayList<>(); /** * 最大最小经纬度的获取 * */ public static double[] getMaxMinLatLng(AMap aMap) { CameraPosition cameraPosition = aMap.getCameraPosition(); LatLng target = cameraPosition.target; float zoom = cameraPosition.zoom; LatLngBounds latlngBounds = aMap.getProjection().getMapBounds(target, zoom); //东北角即地图可视范围右上角经纬度,为屏幕范围内最大 LatLng northeast = latlngBounds.northeast; //西南角即地图可视范围左下角经纬度,为屏幕范围内最小 LatLng sourthwest = latlngBounds.southwest; double maxLat = northeast.latitude; double maxLng = northeast.longitude; double minLat = sourthwest.latitude; double minLng = sourthwest.longitude; return new double[]{maxLat, minLat, maxLng, minLng}; } /** * 添加Marker View * * @param context context * @param startLatLng 经纬度 * @param aMap 高德aMap */ public static void addMarkerToMap(Context context, LatLng startLatLng, String pm_val, int stype, AMap aMap) { @SuppressLint("InflateParams") View view = LayoutInflater.from(context).inflate(R.layout.mymarker, null); TextView tv_val= view.findViewById(R.id.marker_tv_val); switch (stype){ case STYPE_SHOW_MENDIAN: tv_val.setBackgroundResource(R.drawable.icon_mendian); break; case STYPE_SHOW_DINGDAN: tv_val.setBackgroundResource(R.drawable.icon_dingdan); break; case STYPE_SHOW_QISHOU: tv_val.setBackgroundResource(R.drawable.icon_qishou); break; } tv_val.setText(pm_val); BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromView(view); MarkerOptions markerOptions = new MarkerOptions().icon(bitmapDescriptor); if (bitmapDescriptor != null) { if (mOptionList != null) { mOptionList.add(bitmapDescriptor); } } if (view != null) { if (views != null) { views.add(view); } } markerOptions.position(startLatLng); Marker growMarker = aMap.addMarker(markerOptions); if (growMarker != null) { if (markerList != null) { markerList.add(growMarker); } } } public static void addMarkerGroups(Context context, List<LatLng> addressgroups, int resources, final AMap aMap) { for (int i = 0; i < addressgroups.size(); i++) { final MarkerOptions options = new MarkerOptions(); options.position(addressgroups.get(i)); Picasso.with(context).load(resources) // .placeholder(R.drawable.location) // .error(R.drawable.location) .into(new Target() { @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { options.icon(BitmapDescriptorFactory.fromBitmap(bitmap)); aMap.addMarker(options); } @Override public void onBitmapFailed(Drawable errorDrawable) { options.icon(BitmapDescriptorFactory.fromBitmap(((BitmapDrawable) errorDrawable).getBitmap())); aMap.addMarker(options); } @Override public void onPrepareLoad(Drawable placeHolderDrawable) { } }); options.icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory .decodeResource(context.getResources(), resources))); options.draggable(true); makergroup.add(options); } aMap.addMarkers(makergroup, true); } public static void clearIconMarkers() { if (makergroup != null && makergroup.size() > 0) { makergroup.clear(); } if (mOptionList.size() > 0) { try { for (int i = 0; i < mOptionList.size(); i++) { if (null != mOptionList.get(i)) { mOptionList.get(i).recycle(); } } } catch (Exception e) { e.printStackTrace(); } } if (markerList != null && markerList.size() > 0) { markerList.clear(); } if (views != null && views.size() > 0) { for (View view : views) { view = null; } views.clear(); } } }
如此修改,经过我的长时间的测试:
现在的大致运行情况就是这样。虽然没有再因内存而崩溃,但是我既然开始做内存分析,就将深入地了解一下,我接下来将用mat工具去分析内存情况。