混淆文件
将原本正常的项目名称,对其类、方法、字段,重命名a,,b,c,d,从而达到混淆的目的
为什么要混淆?
为了防止apk被轻易反编译,进行apk混淆或进行特殊加密处理,处理后反编译只能看到几行代码和.so的库文件
ANR
application not responding
在Android中对未响应定义如下:
Activity对一个输入事件在5秒内没有响应,
Broadcast Receiver在10秒内没有完成它的onReceiver处理程序.
造成ANR的原因及如何避免:
所有的Android应用程序组件(包括Activity,Service,BroadCast Receiver)都在应用程序主线程中运行,因此任何组件中的费时操作都可能阻塞其他组件,为了确保应用程序能够快速响应应用程序交互或者系统事件,必须将所有的费时处理从应用程序主线程移动到子线程中。
Android多线程机制
为了避免产生ANR现象,在应用程序中通过创建工作线程,将耗时操作移动到工作线程中完成,但是在应用程序组件中Notification和Intent总是在GUI线程(主线程)中进行接收和处理,在GUI线程(主线程)中创建的View或者Toast的显示都应该在GUI线程(主线程)中完成。解决这个矛盾。Android采用了Handler机制来实现工作线程与GUI线程同步,从而更新UI。该模型如下图所示:线程通过Looper建立自己的消息循环,消息队列是一个先入先出的队列,工作线程可以往指定的Handler对象投递消息,主线程的Looper负责从消息队列中取出Message并分发到消息指定目标Handler对象进行处理。详见
http://tbfungeek.github.io/2016/07/06/Android-%E8%BF%9B%E9%98%B6%E4%B9%8B%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%8A%80%E6%9C%AF/
crash原因
1.Java Crash
java代码导致jvm退出,弹出“程序已经崩溃”的对话框,最终用户点击关闭后进程退出。Logcat会在“AndroidRuntime”tag下输出Java的调用栈。
2.Native Crash
窗体泄漏
Android的每一个Activity都有个WindowManager窗体管理器,同样,构建在某个Activity之上的对话框、PopupWindow也有相应的WindowManager窗体管理器。但是它们不能脱离Activity而单独存在着,因为需要Activity的Context,所以当某个Dialog或者某个PopupWindow正在显示的时候我们干掉了承载该Dialog(或PopupWindow)的Activity,就会抛WindowLeaked异常了,因为这个Dialog(或PopupWindow)的WindowManager已经没有谁可以附属了(Context)。
空指针
1.所谓的指针,就是java中的对象的引用。比如String s;这个s就是指针。
2.所谓的空指针,就是指针的内容为空,比如上面的s,如果令它指向null,就是空指针。
3.所谓的空指针异常,就是一个指针是空指针,你还要去操作它,既然它指向的是空对象,它就不能使用这个对象的方法。比如上面的s假如为null,你还要用s的方法,比如s.equals( String x);那么就会产生空指针异常。
OOM内存溢出
Out Of Memory
1.什么是OOM?
通俗讲就是当我们的APP需要申请一块内存用来装图片的时候,系统觉得我们的APP所使用的内存已经够多了,不同意给我们的APP更多的内存,即使手机系统里还有1G空余的内存,然后系统抛出OOM,程序弹框shut down。
一般是由于程序编写者对内存使用不当,如对该释放的内存资源没有释放,导致其一直不能被再次使用而使计算机内存被耗尽的现象。重启计算机即可,但根本解决办法还是对代码进行优化。
2.为什么有OOM,OOM的必然性!
因为android系统app的每个进程或者每个虚拟机有个最大内存限制,如果申请的内存资源超过了这个限制,系统就会抛出OOM错误。跟整个设备的剩余内存没太大关系。比如比较早的android系统一个虚拟机最多16M内存,当一个app启动后,虚拟机不停的申请内存资源用来装载图片,当超过内存上限时就OOM。
3.Android系统APP内存限制怎么确定的?
Android的APP内存组成:
APP内存由dalvik内存和 native内存2部分组成,dalvik也就是 java堆,创建的对象就是在这里分配的,而native是通过 c/c++ 方式申请的内存,Bitmap就是以这种方式分配的(android3.0 以后,系统都默认是通过dalvik分配的,native作为堆来管理)。这2部分加起来不能超过 android 对单个进程、虚拟机的内存限制。
每个手机的内存限制大小是多少?
ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.getMemoryClass();
以上方法会返回以M为单位的数字,不同的系统平台或设备上的值都不太一样,比如:HTC G7默认 24M,Galaxy 36M,emulator-2.3 24M,等等。我的moto xt681 是42M。3.0系统的设备默认是48M。
上面取到是虚拟机的最大内存资源。而对于heap堆的大小限制,可以查看/system/build.prop文件。
dalvik.vm.heapstartsize=5m
dalvik.vm.heapgrowthlimit=48m
dalvik.vm.heapsize=256m
heapsize参数表示单个进程heap可用的最大内存,但如果存在如下参数:
dalvik.vm.heapgrowthlimit=48m表示单个进程heap内存被限定在48m,即程序运行过程中实际只能使用48m内存。
4.为什么android系统设定APP的内存限制?
(1,要使开发者内存使用更为合理。限制每个应用的可用内存上限,可以防止某些应用程序恶意或者无意使用过多的内存,而导致其他应用无法正常运行。Android是有多进程的,如果一个进程(也就是一个应用)耗费过多的内存,其他的应用无法运行了。因为有了限制,使得开发者必须好好利用有限的资源,优化资源的使用。
(2,即使有万千图片、千万数据需要使用到,但是特定时刻需要展示给用户看的总是有限,因为设备的屏幕显示就那么大,上面可以放的信息就是很有限的。大部分信息都是出于准备显示状态,所以没必要给予太多heap内存。也就是出现OOM现象,绝大部分原因是我们的程序设计上有问题,需要优化。比如可以通过时间换空间,不停的加载要用的图片,不停的回收不用的图片,把大图片解析到适合手机屏幕大小的图片等。
(3,android上的APP使用独立虚拟机,每开一个应用就会打开至少一个独立的虚拟机。这样可以避免虚拟机崩溃导致整个系统崩溃,同时代价就是需要浪费更多内存。这些设计确保了android的稳定性。
5.不是android有gc会自动回收资源么,为什么还会OOM?
Android不是用gc会自动回收资源么,为什么app的哪些不用的资源不回收呢?
Android的gc会按照特定的算法回收程序不用的内存资源,避免app的内存申请越积越多。但是Gc一般回收的资源是哪些无主的对象内存或者软引用的资源,或者更软的引用资源,比如:
Bitmap bt= BitmapFactory.decodeResource(this.getResources(),R.drawable.splash);
使用bt…//此时的图片资源是强应用,是有主的资源。
bt=null;
此时这个图片资源就是无主的了,gc心情好的时候就会去回收它。
GC(Garbage Collection):
在老式的C/C++程序中,程序员定义了一个变量,就是在内存中开辟了一段相应的空间来存值。由于内存是有限的,所以当程序不再需要使用某个变量的时候,就需要销毁该对象并释放其所占用的内存资源,好重新利用这段空间。在C/C++中,释放无用变量内存空间的事情需要由程序员自己来处理。就是说当程序员认为变量没用了,就手动地释放其占用的内存。但是这样显然非常繁琐,如果有所遗漏,就可能造成资源浪费甚至内存泄露。当软件系统比较复杂,变量多的时候程序员往往就忘记释放内存或者在不该释放的时候释放内存了。
有了GC,程序员就不需要再手动的去控制内存的释放。当Java虚拟机(VM)或.NETCLR发觉内存资源紧张的时候,就会自动地去清理无用对象(没有被引用到的对象)所占用的内存空间(这里的说法略显粗略,事实上何时清理内存是个复杂的策略)。如果需要,可以在程序中显式地使用System.gc() / System.GC.Collect()来强制进行一次立即的内存清理。Java提供的GC功能可以自动监测对象是否超过了作用域,从而达到自动回收内存的目的,Java的GC会自动进行管理,调用方法:System.gc() 或者Runtime.getRuntime().gc();
Java垃圾回收机制
Jvm(Java虚拟机)内存模型:Jvm(Java虚拟机)主要管理两种类型内存:堆和非堆。
堆是运行时数据区域,所有类实例和数组的内存均从此处分配。
非堆是JVM留给自己用的,包含方法区、JVM内部处理或优化所需的内存(如 JIT Compiler,Just-in-time Compiler,即时编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码。
总之,java程序内存主要(这里强调主要二字)分两部分,堆和非堆。大家一般new的对象和数组都是在堆中的,而GC主要回收的内存也是这块堆内存。
堆内存(Heap Memory): 存放Java对象
非堆内存(Non-Heap Memory): 存放类加载信息和其它meta-data
其它(Other): 存放JVM 自身代码等
堆内存由垃圾回收器的自动内存管理系统回收。
一块 Java 堆空间一般分成三部分,这三部分用来存储三类数据:
- 刚刚创建的对象。在代码运行时会持续不断地创造新的对象,这些新创建的对象会被统一放在一起。因为有很多局部变量等在新创建后很快会变成 不可达 的对象,快速死去 ,因此这块区域的特点是 存活对象少,垃圾多 。形象点描述这块区域为: 新生代;
- 存活了一段时间的对象。这些对象早早就被创建了,而且一直活了下来。我们把这些 存活时间较长 的对象放在一起,它们的特点是 存活对象多,垃圾少 。形象点描述这块区域为: 老年代;
- 永久存在的对象。比如一些静态文件,这些对象的特点是不需要垃圾回收,永远存活。形象点描述这块区域为:永久代 。(不过在 Java 8 里已经把 永久代 删除了,把这块内存空间给了 元空间,后续文章再讲解。)
也就是说,常规的 Java 堆至少包括了 新生代 和 老年代 两块内存区域,而且这两块区域有很明显的特征:
- 新生代:存活对象少、垃圾多
- 老年代:存活对象多、垃圾少
堆内存分为两大部分:新生代和老年代。比例为1:2。
老年代主要存放应用程序中生命周期长的存活对象。
新生代又分为三个部分:一个Eden区和两个Survivor区,比例为8:1:1。
Eden区存放新生的对象。
Survivor存放每次垃圾回收后存活的对象。
屏幕纵横比适配
一般手机的屏幕纵横比为16:9,如1080x1920、1440x2560等,其比值为1.777777……,全面屏手机出现之前,Android中默认的最大屏幕纵横比(maximum aspect ratio)为1.86,即能够兼容16:9的屏幕。
现在一些手机厂商为了追求更大的屏幕空间以及更极致的用户体验,于是提高了屏幕纵横比,17:9、19:10、18:9、18.5:9的手机开始进入市场,这些手机被称为全面屏手机。
目前Galaxy S8及S8+的18.5:9,18.5:9=2.055555555…,则需要在manifest.xml文件中修改max_aspect=2.1,若部分厂商需要适配到2.3
<meta-data android:name="android.max_aspect" android:value="2.3" />