Android OOM分析
OOM,即内存溢出,是因应用所需内存超过系统分配阈值,导致抛出的书法生成源码java.lang.OutOfMemoryError错误。其根本原因在于开发者不当的内存使用。
Android内存管理基于GenerationalHeapMemory模型,新对象存于YoungGeneration区域。当对象在该区域停留至一定时间,会迁移到OldGeneration,最终在达到一定时间后转移至PermanentGeneration区域。
系统会根据内存中不同数据类型执行特定的GC操作。新分配到YoungGeneration的对象更易被销毁,YoungGeneration的GC操作速度通常快于OldGeneration。每个Generation内存固定大小,新对象持续添加,aop切面源码接近内存阈值时触发GC,腾出空间存放更多对象。GC执行时,所有线程都会暂停。GC时间长短与执行的Generation类型和区域内对象数量有关。
Android系统为每个应用设置最大DalvikHeapSize阈值,根据设备RAM大小而异。接近阈值时,再分配内存易引发OutOfMemoryError。
触发OOM的条件是allocated内存加上新分配内存等于或超过getMemoryClass()值。
避免OOM方法包括减少对象内存占用、使用高效数据结构、避免使用Enum、减小Bitmap占用、重复利用对象。
推荐使用ArrayMap和SparseArray替代HashMap,天火源码它们在大多数情况下效率更高、内存使用更少。避免在Android中使用枚举,使用更小以减少Bitmap占用。在程序中创建对象池或利用系统框架的复用特性来减少对象创建。
Android系统内置资源如字符串、颜色、等可以直接使用,减小APK大小。注意在ListView/GridView等视图中对ConvertView复用,在RecyclerView、ListView、GridView中使用LRU机制缓存Bitmap,利用inBitmap特性提高内存使用效率。
避免在onDraw方法中执行对象创建,使用StringBuilder替代频繁的放置海岛源码字符串拼接。
注意避免内存泄漏,如注意Activity泄漏、使用Application Context、及时回收临时Bitmap对象、注销监听器、管理缓存容器中的对象、适时销毁WebView、确保Cursor关闭。
深入了解内存管理与避免内存泄漏对优化Android应用性能至关重要。
内存优化之ArrayMap、SparseArray、SparseIntArray
作者:众小成多积小致巨
1、前言
这几个数据结构是Android系统为了节约内存而设计的。它们在系统中广泛使用,是跟随Google技术路线并扩展对数据结构理解的必要工具。ArrayMap、egret海报源码SparseArray 和 SparseIntArray,虽然名称相似,但各自针对不同的存储需求。ArrayMap是一个解决 HashMap 存储效率问题的映射数据结构,SparseArray和SparseXXXArray则是为稀疏数据设计的数组结构,其中xxx代表基本数据类型,避免了对象间的自动拆装箱操作,提高了效率。本文将重点介绍SparseIntArray,其他两个结构有相似特点和原理。
2、存储结构
ArrayMap采用两个数组存储,一个用于存放键的哈希值,另一个用于存放键值对。通过索引映射,每个键的哈希值的偶数位置存放键,奇数位置存放对应的值。mHashes数组按从小到大顺序存储,以保证键的有序性。
SparseArray同样采用两个数组结构,一个用于存储数组索引作为键,另一个用于存储具体数据作为值。mKeys数组同样按从小到大顺序存储,用于快速查找。
尽管结构思想相似,但实现细节有所不同,如哈希计算、存储容量的动态调整等。
3、ArrayMap特点
ArrayMap具有哈希计算功能,支持键为null的情况,此时哈希值默认为0。对于非null键,其哈希值计算依赖于构造器中指定的规则,默认为false。在设计hashCode方法时,如果键对象是固定的或不同的,应确保哈希值也保持一致,以保持排序有序。
ArrayMap的容器大小管理通过缓存机制实现,使用两个数组mBaseCache和mTwiceBaseCache。初始化时,mBaseCache容量为8,mTwiceBaseCache容量为。每个缓存最多可存储个元素,且存储容量为数组容量的一半。在添加或删除元素时,容器大小可能需要调整,同时系统会处理数组移动和废弃数组的回收,以优化内存使用。
ArrayMap支持快速查找、插入或替换数据,通过正整数索引快速定位已有数据或找到插入位置,负整数表示该位置为空,适合稀疏数据场景。
在添加数据时,ArrayMap可能会触发容器扩容操作,以适应数据增长。当容器已满且需要添加新数据时,也会执行扩容。同样,在删除数据后,容器可能会减少容量,以优化内存占用。
4、SparseIntArray
SparseIntArray在理解了ArrayMap的基础上,具有相似的存储机制和查找特性,但针对的是整型键的稀疏数组场景。与ArrayMap相比,SparseIntArray在内存管理上更加专注于整型键的高效存储与快速访问,而没有GC方法机制,且存储的是整型值而非对象。
5、SparseArray和SparseXXXArray
SparseArray和SparseXXXArray设计目标相似,都旨在优化稀疏数据的存储和访问效率。SparseXXXArray(例如SparseIntArray)在实现上与SparseArray存在差异,主要体现在内存管理机制和数据类型上。SparseXXXArray没有GC(垃圾回收)方法,且存储的是对应基本数据类型的数据,如整型。其存储机制更加精简,适用于对内存使用和性能有严格要求的场景。
通过本文的介绍,读者可以了解到Android系统中几种关键数据结构的设计思路与特点,它们在不同场景下提供高效的数据存储与访问能力,是Android应用开发中不可或缺的工具。
Linux 统计代码行数的代码
统计文件行数(单个文件):
wc -l file
例如:
homer@ubuntu:~/workspace/Android/game$ wc -l LGameAndroid2DActivity.Java
LGameAndroid2DActivity.java
统计目录所有文件行数(全部目录):
find . -name *.java | xargs wc -l
例如:
homer@ubuntu:~/workspace/android$ find . -name *.java | xargs wc -l
./game/core/LHandler.java
./game/core/LFlicker.java
...
./game/utils/collection/ArrayMap.java
./game/utils/CollisionUtils.java
./game/utils/NumberUtils.java
total
统计目录并按行数排序(按行大小排序):
find . -name *.java | xargs wc -l | sort -n
homer@ubuntu:~/workspace/android$ find . -name *.java | xargs wc -l | sort -n
./game/action/sprite/Collidable.java
./game/core/graphics/component/CollisionQuery.java
./game/core/graphics/filter/ImageFilter.java
./game/LMode.java
...
./game/core/geom/Path2D.java
./game/core/graphics/Screen.java
./game/core/graphics/device/LGraphics.java
./game/core/geom/AffineTransform.java
total
统计目录并按行数排序(按行文件名排序):
find . -name *.java | xargs wc -l | sort -k2
homer@ubuntu:~/workspace/android$ find . -name *.java | xargs wc -l | sort -k2
./game/action/ActionControl.java
./game/action/ActionEvent.java
./game/action/ActionListener.java
....
./game/utils/NumberUtils.java
./game/utils/RecordStoreUtils.java
./game/utils/ScreenUtils.java
./game/utils/StringUtils.java
total
2024-11-30 18:11
2024-11-30 17:58
2024-11-30 17:56
2024-11-30 16:12
2024-11-30 16:05