android 内存 alloc,移动学习 AndroidStudio内存优化分析—alloc文件分析

通过Androidstudio分析移动学习不做任何操作时的内存分配及占用情况

1、点击“start Allocation Tracking"5-10秒后再次点击,生成.allc文件:

e8f18e5b7c2a1b8c35e33c53e5ce19d5.png

2、用group by Method的方式看线程 6814:

4242dc4b754be5b7efec0d1731233c2b.png

3、是netty线程在接收read消息时站的内存,主要是newHeapBuffer()构造函数初始化时占用内存,查了一下:

Netty包含三种ByteBuf:

HEAP BUFFERS:

The most used type is the ByteBuf that stores its data in the heap space of the JVM. This is done by storing it in a backing array. This type is fast to allocate and also de-allocate when you re not using a pool. It also offers a way to directly access the backing array, which may make it easier to interact with legacy code .

DIRECT BUFFERS

Another ByteBuf implementation is the direct one. Direct means that it allocates the memory directly, which is outside the heap . You won't see its memory usage in your heap space. You must take this into account when calculating the maximum amount of memory your application will use and how to limit it, as the max heap size won t be enough. Direct buffers on the other side are optimal when it s time to transfer data over a socket. In fact, if you use a nondirect buffer, the JVM will make a copy of your buffer to a direct buffer internally before sending it over the socket.

The down side of direct buffers is that they re more expensive to allocate and de-allocate compared to heap buffers. This is one of the reasons why Netty supports pooling, which makes this problem disappear. Another possible down side can be that you re no longer able to access the data via the backing array, so you ll need to make a copy of the data if it needs to work with legacy code that requires this.

COMPOSITE BUFFERS

The last ByteBuf implementation you may be confronted with is the CompositeByteBuf. This does exactly what its name says; it allows you to compose different ByteBuf instances and provides aview over them. The good thing is you can also add and remove them on-the-fly, so it s kind of like a List.

For example, a message could be composed of two parts: header and body. In a modularized application, the two parts could be produced by different modules and assembled later when the message is sent out. Also, you may use the same body all the time and just change the header. So it would make sense here to not allocate a new buffer every time.

This would be a perfect fit for a CompositeByteBuf asno memory copy will be needed and the same API could be used

4、HeapBuffer是Netty用来进行data存储的主要类,暂时管不了

5、看线程6766

c4fe984169e865a6efa0faaa83927a83.png

6、有点傻眼,有一半都是关于simpleDateFomate类的方法,挨个看吧,先看run():505

6cc153b311222d4c53f0bbee6923fc8b.png

5bbf7cb3b9ee34fe542df3a3bd9d0df6.png

7、主要都是service中的dateFormat和StringBuffer,而StringBuffer用的不多,内存和分配次数也没占多少,全都是DateFormat

8、线程6766中,除run()505外基本都是DateFormat函数分配的内存太多,要人命啊。找了找service中的代码:

class TimerRunnable implements RunFunction {

@SuppressWarnings("deprecation")

@Override

public void timerRun() {// 主业务逻辑

Log.i(TAG, "智能教学管理系统:后台运行,当前运行时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

.........

9、每10秒执行一次的时候都会调用一次,而在相关业务逻辑的计算时都是new出来的。好可怕

10、找到了一篇文章:https://www.bbsmax.com/A/kvJ3eb3ndg/ simpleDateFormat是非线程安全的,在多并发时会有问题,照着博主的代码改一下,在此表示感谢:

public class ThreadLocalDateUtil {

private static final String date_format = "yyyy-MM-dd HH:mm:ss";

private static ThreadLocal threadLocal = new ThreadLocal();

public static DateFormat getDateFormat()

{

DateFormat df = threadLocal.get();

if(df==null){

df = new SimpleDateFormat(date_format);

threadLocal.set(df);

}

return df;

}

public static String formatDate(Date date) throws ParseException {

return getDateFormat().format(date);

}

public static Date parse(String strDate) throws ParseException {

return getDateFormat().parse(strDate);

}

}

11、再次运行程序 ,完美!完全没有了dateformat占用大量内存的问题

12、发现在mainLoop()中有两处内存泄露:

7cdedb92f655bdcec6d528671e527268.png

13、是查询数据库是,cursor的内存泄露,原来的cursor写法:

Cursor cursor = mDatabase.rawQuery("select courseId, courseName, courseTimeId, createTime, leaveEnd, leaveId, leaveReason, leaverId, leaveStart, leaveStatus, orgName, typeId, typeName, userName from QingjiaTable where leaverId = ?", new String[]{userid});

while (cursor.moveToNext()) {

QingjiaModel qm = new QingjiaModel();

....

qm.setUserName(cursor.getString(0...13));

qmList.add(qm);

}

cursor.close();

14现改为:

Cursor cursor =null;

try{

cursor = mDatabase.rawQuery("select courseId, courseName, courseTimeId, createTime, leaveEnd, leaveId, leaveReason, leaverId, leaveStart, leaveStatus, orgName, typeId, typeName, userName from QingjiaTable where leaverId = ?", new String[]{userid});

while (cursor != null && cursor.moveToNext()) {

QingjiaModel qm = new QingjiaModel();

qm.setUserName(cursor.getString(0...13));

qmList.add(qm);

}

}finally{

if(cursor != null){

cursor.close();

}

}

15、再次运行程序,完美!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值