android加载java,Android中Java类加载耗时问题

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

自己的练习项目Brush,是一个功能简单的绘制书写应用,在最后一个提交add simulate after launch之前,都存在一个问题,就是每次启动应用后,绘制第一条曲线的开始部分都是直线。

brush.png原因是Android会根据应用的处理能力(UI线程的处理速度),控制MotionEvent的上报频率,也就是onTouchEvent的触发频率。如果在UI线程中处理了耗时任务,那么onTouchEvent的触发频率就会非常低,在这种情况下,只通过MotionEvent的getX和getY方法来获取坐标值,根据数量极少的坐标点绘制贝塞尔曲线,有时就会出现近似直线的情况。Brush绘制第一条曲线的开始部分都是直线的问题,可以肯定的是UI线程中做了耗时操作,而且只有第一次中才存在。经过各种尝试,最后确定了是Java类加载耗时造成的。

Java类加载

对于Java类加载,先看看别人是怎么理解的:Java类加载机制 Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等,Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能。

虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

在Android中app运行时并不会把所有的类一次性全部加载到虚拟机中,而是需要用到时才去加载,来看看加载一个类加载耗时的问题:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22/* MainActivity.java */

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

long time = System.nanoTime();

ClassLoadTest.callOnTime(time);

try {

Thread.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

time = System.nanoTime();

ClassLoadTest.callOnTime(time);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14/* ClassLoadTest */

public class ClassLoadTest {

private static final String TAG = ClassLoadTest.class.getSimpleName();

static {

Log.i(TAG, "init");

}

public static void callOnTime(long time) {

long useTime = System.nanoTime() - time;

Log.i(TAG, "callOnTime use:" + useTime + "ns");

}

}

非常小的一个类,主要检测开始调用方法到进入方法内部开始执行所花费的时间。这个应用运行在设备LGE Nexus 5X (Android 8.0.0, API 26)上,看一下日志输出:1

2

309-01 16:33:41.656 15291-15291/me.huntto.classloadtest I/ClassLoadTest: init

callOnTime use:1206198ns

09-01 16:33:41.658 15291-15291/me.huntto.classloadtest I/ClassLoadTest: callOnTime use:7344ns

可以看到两次的时间不是一个数量级的,第一次是毫秒级,第二次是微秒级。如果callOnTime方法里面使用了其他类,并且也是第一次加载,那么整个调用链第一次花费的时间将更长。

解决问题

类加载本来就是一个耗时的操作,如果要解决它,需要留给优化虚拟机的专家们。对于普通应用开发者来说,最好的解决方法就是规避问题。

如文章开头提到Brush就是对类加载耗时问题比较敏感。ClassLoadTest中要让每次callOnTime打印的时间不至于相差太大,可以让ClassLoadTest提前加载:1

2

3

4

5

6

7

8

9/* MainActivity.java */

public class MainActivity extends AppCompatActivity {

static {

ClassLoadTest.load();

}

...

}

1

2

3

4

5

6

7

8/* ClassLoadTest */

public class ClassLoadTest {

...

public static void load() {

}

...

}1

2

309-01 16:48:32.929 15899-15899/me.huntto.classloadtest I/ClassLoadTest: init

09-01 16:48:33.314 15899-15899/me.huntto.classloadtest I/ClassLoadTest: callOnTime use:8855ns

09-01 16:48:33.316 15899-15899/me.huntto.classloadtest I/ClassLoadTest: callOnTime use:7240ns

可见callOnTime的时间差已经是微秒级的了。

后记

由于Java类加载比较耗时,所以要避免一次加载过多类,造成程序卡顿的现象,应该适时的加载适量的类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值