GC_FOR_MALLOC

本文详细解释了Android中垃圾回收(GC)的各种触发原因,包括GC_FOR_MALLOC、GC_EXPLICIT、GC_CONCURRENT及GC_EXTERNAL_ALLOC等,并说明了这些类型在运行时的具体表现。此外,还介绍了如何监控和管理Java堆内存与Native内存,以避免出现内存溢出问题。

GC_FOR_MALLOC means that the GC was triggered because there wasn't enough memory left on the heap to perform an allocation. Might be triggered when new objects are being created.

GC_EXPLICIT means that the garbage collector has been explicitly asked to collect, instead of being triggered by high water marks in the heap. Happens all over the place, but most likely when a thread is being killed or when a binder communication is taken down.

There are a few others as well:

GC_CONCURRENT Triggered when the heap has reached a certain amount of objects to collect.

GC_EXTERNAL_ALLOC means that the the VM is trying to reduce the amount of memory used for collectable objects, to make room for more non-collectable.

 

 

typedefenum{ 
    /* Not enough space for an "ordinary" Object to be allocated. */ 
    GC_FOR_MALLOC, 
    /* Automatic GC triggered by exceeding a heap occupancy threshold. */ 
    GC_CONCURRENT, 
    /* Explicit GC via Runtime.gc(), VMRuntime.gc(), or SIGUSR1. */ 
    GC_EXPLICIT, 
    /* GC to try to reduce heap footprint to allow more non-GC'ed memory. */ 
    GC_EXTERNAL_ALLOC, 
    /* GC to dump heap contents to a file, only used under WITH_HPROF */ 
    GC_HPROF_DUMP_HEAP 
}GcReason

 

 

GC_EXTERNAL_ALLOC freed 297K, 49% free 3411K/6663K, external 24870K/26260K, paused 83ms

前面Free的内存是VM中java使用的内存,external是指VM中通过JNI中Native的类中的malloc分配出的内存,例如Bitmap和一些Cursor都是这么分配的。
在Davilk中,给一个程序分配的内存根据机型厂商的不同,而不同,现在的大部分的是32M了,而在VM内部会把这些内存分成java使用的内存和 Native使用的内存,它们之间是不能共享的,就是说当你的Native内存用完了,现在Java又有空闲的内存,这时Native会重新像VM申请,而不是直接使用java的。
例如上边的例子
free 3411K/6663K和external 24870K/26260K
如果这时需要创建一个2M的Bitmap,Native现有内存26260-24870=1390K<2048k,因此他就会向Vm申请内存,虽然java空闲的内存是
6663-3411=3252>2048,但这部分内存Native是不能使用。
但是你现在去申请2M的Native内存,VM会告诉你无法分配的,因为现在已使用的内存已经接近峰值了32M(26260+6663=32923 ),所以现在就会成force close 报OOM。
所以现在我们要检查我们的native内存的使用情况来避免OOM。

 

转至:http://hi.baidu.com/qmiao128/blog/item/69f2fa31d4a5d3b05fdf0ed2.html

 

void lv_draw_mask_radius_init(lv_draw_mask_radius_param_t * param, const lv_area_t * rect, lv_coord_t radius, bool inv) { lv_coord_t w = lv_area_get_width(rect); lv_coord_t h = lv_area_get_height(rect); int32_t short_side = LV_MIN(w, h); if(radius > short_side >> 1) radius = short_side >> 1; if(radius < 0) radius = 0; lv_area_copy(&param->cfg.rect, rect); param->cfg.radius = radius; param->cfg.outer = inv ? 1 : 0; param->dsc.cb = (lv_draw_mask_xcb_t)lv_draw_mask_radius; param->dsc.type = LV_DRAW_MASK_TYPE_RADIUS; if(radius == 0) { param->circle = NULL; return; } uint32_t i; /*Try to reuse a circle cache entry*/ for(i = 0; i < LV_CIRCLE_CACHE_SIZE; i++) { if(LV_GC_ROOT(_lv_circle_cache[i]).radius == radius) { LV_GC_ROOT(_lv_circle_cache[i]).used_cnt++; CIRCLE_CACHE_AGING(LV_GC_ROOT(_lv_circle_cache[i]).life, radius); param->circle = &LV_GC_ROOT(_lv_circle_cache[i]); return; } } /*If not found find a free entry with lowest life*/ _lv_draw_mask_radius_circle_dsc_t * entry = NULL; for(i = 0; i < LV_CIRCLE_CACHE_SIZE; i++) { if(LV_GC_ROOT(_lv_circle_cache[i]).used_cnt == 0) { if(!entry) entry = &LV_GC_ROOT(_lv_circle_cache[i]); else if(LV_GC_ROOT(_lv_circle_cache[i]).life < entry->life) entry = &LV_GC_ROOT(_lv_circle_cache[i]); } } if(!entry) { entry = lv_mem_alloc(sizeof(_lv_draw_mask_radius_circle_dsc_t)); LV_ASSERT_MALLOC(entry); lv_memset_00(entry, sizeof(_lv_draw_mask_radius_circle_dsc_t)); entry->life = -1; } else { entry->used_cnt++; entry->life = 0; CIRCLE_CACHE_AGING(entry->life, radius); } param->circle = entry; circ_calc_aa4(param->circle, radius); }讲解代码
最新发布
04-03
这段代码是一个用于初始化圆角遮罩绘制参数的函数 `lv_draw_mask_radius_init` 的实现。它主要用于图形界面库 LittlevGL 中的掩码处理功能,通过设置矩形区域、半径以及缓存机制等信息来生成圆角效果。 ### 功能解析 #### 函数输入参数 - **param** (`lv_draw_mask_radius_param_t *`) 指向存储圆形遮罩参数的数据结构指针。 - **rect** (`const lv_area_t *`) 矩形区域的信息(例如 x 和 y 坐标范围),表示需要应用圆角效果的矩形边界框。 - **radius** (`lv_coord_t`) 圆角的半径值,控制边界的弯曲程度。 - **inv** (`bool`) 是否反转遮罩的效果标志位,如果为真,则会将外侧作为有效区域。 --- #### 具体步骤分析 1. **获取宽高并限制最大半径** ```c lv_coord_t w = lv_area_get_width(rect); lv_coord_t h = lv_area_get_height(rect); int32_t short_side = LV_MIN(w, h); if(radius > short_side >> 1) radius = short_side >> 1; ``` - 获取传入矩形的宽度和高度。 - 计算较短的一条边长,并将其一半设为允许的最大半径值(防止超出实际尺寸)。 2. **检查负数半径情况** 如果用户传递了一个负值给半径变量,则直接将其置零,避免无效配置: ```c if(radius < 0) radius = 0; ``` 3. **填充基础数据到参数结构体内** 将指定矩形区域复制至内部缓冲区同时记录调整后的圆角大小及是否反向外延标记位: ```c lv_area_copy(&param->cfg.rect, rect); param->cfg.radius = radius; param->cfg.outer = inv ? 1 : 0; param->dsc.cb = (lv_draw_mask_xcb_t)lv_draw_mask_radius; param->dsc.type = LV_DRAW_MASK_TYPE_RADIUS; ``` 4. **特殊情形处理——当无任何曲率需求时提前退出流程** 若最终确定下来的圆角量级归于平直状态即“完全方形”则无需再分配额外资源亦不必构建相应的辅助描述符对象而仅需清空对应字段即可结束整个操作过程; ```c if(radius == 0){ param->circle=NULL; return ; } ``` 5. **尝试复用现有缓存项完成快速匹配任务优化性能表现减少动态内存申请次数提升运行效率降低成本消耗延长系统寿命等等优势多多值得拥有哟~😊** 首先遍历所有可用预定义好的固定容量数组元素逐一比较看是否有相同规格实例可供再次利用若是发现满足条件就增加其引用计数值更新生命周期统计数据并且把该位置地址赋给目标参数便于后续进一步调用访问之用;如果没有找到合适的候选者才会继续向下寻找其他解决方案比如创建新的实体加入队列之中等待未来某个时刻能够释放出来供别的模块共享使用等情况发生啦! ```c /*Try to reuse a circle cache entry*/ for(i=0;i<LV_CIRCLE_CACHE_SIZE;i++){ ...... } ``` 6. **未能命中已知快照集合的情况下采取备用策略新建独立副本保存相关信息以便长期保留直至不再被频繁请求为止才考虑彻底销毁回收所占用的空间资源以维持总体平衡稳定局面达成既定目的为止哦🎉** 当上述检索环节均未果时就会触发这条分支逻辑进而从堆上开辟出一块新领地专门存放当前所需的所有必要组成部分并通过适当手段加以保护确保不会因为意外丢失导致程序崩溃异常等问题出现呢😎 ```c if(!entry){ entry = lv_mem_alloc(sizeof(_lv_draw_mask_radius_circle_dsc_t)); LV_ASSERT_MALLOC(entry); lv_memset_00(entry,sizeof(_lv_draw_mask_radius_circle_dsc_t )); entry->life=-1; }else{...} ``` 7. **最后一步总是少不了关键性的收尾动作那就是计算抗锯齿因子并将结果反馈回去形成完整的闭环构造图元渲染引擎得以正常运作起来呈现完美视觉盛宴就给大家欣赏吧🌈✨** --- ### 总结说明: 这个函数的核心思想在于充分利用局部变量临时寄存器以及全局静态表单相结合的方式最大限度节省了不必要的开销同时也兼顾到了极端特殊情况下的兼容性和鲁棒性从而保证了整体架构设计合理科学实用性强易于维护等特点突出体现了现代软件工程实践过程中追求卓越品质不懈努力的精神风貌👏👍!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值