Android内存管理基础
2015-08-07 09:34
489 查看
虚拟内存:将外存储器的部分空间作为内存的扩展,资源不足时按算法保存起来 当要用到数据块时交换回内存。
逻辑地址=Segment Selector + Offset;
Segment Selector: INDEX + TI(Table Indicator) + PRL(段选择子)用于描述逻辑地址所处的段
INDEX : 用来得到段描述符在GDT或LDT中的偏移
TI 0代表GDT 1代表LDT GDT (存储地址由GDTR寄存器保存) LDT (存储地址由LDTR寄存器保存)
PRL : 请求特权级
Offset : 用于描述段内的偏移值
CPU提供专门的寄存器来承载选择子;CS代码 DS全局与静态数据 SS堆栈 ES附加数据段 (FS GS通用寄存器)
* (早期)Real Mode And Protected Mode(开机前实模式,开机后保护模式)*
线性地址
(段选择子作用)根据TI获取段描述符确定存储的寄存器,根据INDEX获取对应的寄存器偏移量后的段基地址(偏移量作用)由段基地址+段内偏移值得到线性地址。
物理地址
页:分页操作的对象是固定大小的内存块,页是内存的一个概念。页框:页框与页的大小一样为4KB,他是物理地址的一个概念。页框与页分散对应。
缺失页:系统通过算法回收那些没有与页框对应的页。从而调出内存。
Android系统内存分配和回收
Native层智能指针的实现原理规避对象的产生和销毁
Java层
相对C层做出了一定的努力,并对Android内存提供了管理机制
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
start:映射区的开始地址
length:映射区的长度。
prot:期望的内存保护标志(操作权限)
flags:指定程序对内存块的影响。
fd:有效的文件描述词。一般是由open()函数返回
offset:被映射文件内存起点。
mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,
最后一个页不被使用的空间将会清零。
Android Low memory killer (LMK驱动)
Linux的OOM要等到系统严重缺失可用内存时才会调用。Android修改该机制,采用了分级的Killer, 源码位置${kernel}\drivers\staging\android\lowmemorykiller.c注册lowmemory_shrinker方法。当达到某一级的时候执行该回调
exp:比如当值为6MB的时候,需要清理OOM SCORE为0的进程。
/**以下代码为kernel3.8_为例*/ static int __init lowmem_init(void) { task_free_register(&task_nb); register_shrinker(&lowmem_shrinker); return 0; } //表示某一级要处理的对应的进程数 static int lowmem_adj[6] = { 0, 1, 6, 12, }; static int lowmem_adj_size = 4;//页大小 //表示当剩下内存少于对应级别时,执行清理操作。 static size_t lowmem_minfree[6] = { 3 * 512, /* 6MB */ 2 * 1024, /* 8MB */ 4 * 1024, /* 16MB */ 16 * 1024, /* 64MB */ }; static int lowmem_minfree_size = 4;
3.如何知道需要被清理的进程,如下 Android定义了一系列的ADJ
static final int EMPTY_APP_ADJ = 15; //当前只运行了不可见Activity组件的进程 static final int HIDDEN_APP_MAX_ADJ = 15; static int HIDDEN_APP_MIN_ADJ = 7; //Luancher进程 static final int HOME_APP_ADJ = 6; // 2级服务 // system/rootdir/init.rc on startup. static final int SECONDARY_SERVER_ADJ = 5; // 承载backup相关操作进程 static final int BACKUP_APP_ADJ = 4; // 重量级应用程序进程 static final int HE***Y_WEIGHT_APP_ADJ = 3; // This is a process only hosting components that are perceptible to the // user, and we really want to avoid killing them, but they are not // immediately visible. An example is background music playback. Value set in // system/rootdir/init.rc on startup. static final int PERCEPTIBLE_APP_ADJ = 2; // 前台可见进程 static final int VISIBLE_APP_ADJ = 1; // 前台运行与用户交互的进程 static final int FOREGROUND_APP_ADJ = 0; // 核心进程 如telephony进程 static final int CORE_SERVER_ADJ = -12; // 系统进程 static final int SYSTEM_ADJ = -16;
4.可以通过文件修改某个进程对应ADJ值。也可以在application标签中添加android:persistent=true属性,
此属性是将程序设置为常驻内存.
Android 匿名共享内存Anonymous Shared Momery
定义:将制定的物理地址映射到各个进程的虚拟地址空间中。//early-init时加载ashmem.c文件 如下调用ashmem_init static int __init ashmem_init(void) { //通过kmem_cache_create创建的kmem_cache //它的类型是struct kmem_cache,表示这是一个slab缓冲区,由内核中的内存管理系统进行管理。 ashmem_area_cachep = kmem_cache_create("ashmem_area_cache", sizeof(struct ashmem_area), 0, 0, NULL); ashmem_range_cachep = kmem_cache_create("ashmem_range_cache", sizeof(struct ashmem_range), 0, 0, NULL); ret = misc_register(&ashmem_misc); register_shrinker(&ashmem_shrinker); printk(KERN_INFO "ashmem: initialized\n"); return 0; } //ashmem时一个杂项设备(misc device),他调用ashmem_misc注册 static struct miscdevice ashmem_misc = { .minor = MISC_DYNAMIC_MINOR, .name = "ashmem", .fops = &ashmem_fops, }; //定义了进程间匿名共享内存的分配步骤ashmem_open,ashmem_ioctl,ashmem_mmap,ashmem_release static struct file_operations ashmem_fops = { .owner = THIS_MODULE, .open = ashmem_open, .release = ashmem_release, .read = ashmem_read, .llseek = ashmem_llseek, .mmap = ashmem_mmap, .unlocked_ioctl = ashmem_ioctl, .compat_ioctl = ashmem_ioctl, }; struct ashmem_area { char name[ASHMEM_FULL_NAME_LEN];// 这个名字会显示/proc/<pid>/maps文件中,<pid>表示打开这个共享内存文件的进程ID struct list_head unpinned_list; // 列表头,它把这块共享内存中所有被解锁的内存块连接在一起 struct file *file; // 域file表示这个共享内存在临时文件系统tmpfs中对应的文件 size_t size; /* size of the mapping, in bytes */ unsigned long prot_mask; // 表示这块共享内存的访问保护位。 }; //创建内存指定文件,操作内存即操作文件 static int ashmem_open(struct inode *inode, struct file *file) { struct ashmem_area *asma; int ret; ret = generic_file_open(inode, file); if (unlikely(ret)) return ret; //从ashmem_area_cachep分配一块ashmem_area内存 asma = kmem_cache_zalloc(ashmem_area_cachep, GFP_KERNEL); if (unlikely(!asma)) return -ENOMEM; //设置名字 权限等 INIT_LIST_HEAD(&asma->unpinned_list); memcpy(asma->name, ASHMEM_NAME_PREFIX, ASHMEM_NAME_PREFIX_LEN); asma->prot_mask = PROT_MASK; //记录在private_data中 file->private_data = asma; return 0; } //为每个子模块创建单独的内存 static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ashmem_area *asma = file->private_data; long ret = -ENOTTY; switch (cmd) { case ASHMEM_SET_NAME: ret = set_name(asma, (void __user *) arg); break; case ASHMEM_GET_NAME: ret = get_name(asma, (void __user *) arg); break; case ASHMEM_SET_SIZE: ret = -EINVAL; if (!asma->file) { ret = 0; asma->size = (size_t) arg; } break; ... break; } return ret; } //执行对子模块的映射 static int ashmem_mmap(struct file *file, struct vm_area_struct *vma) { struct ashmem_area *asma = file->private_data; int ret = 0; mutex_lock(&ashmem_mutex);//互斥锁 /* 通过ioctl设置大小 */ if (unlikely(!asma->size)) { ret = -EINVAL; goto out; } //请求的权限保护必须匹配我们设定的权限值 if (unlikely((vma->vm_flags & ~calc_vm_prot_bits(asma->prot_mask)) & calc_vm_prot_bits(PROT_MASK))) { ret = -EPERM; goto out; } vma->vm_flags &= ~calc_vm_may_flags(~asma->prot_mask); if (!asma->file) {//创建asm的临时支持文件 char *name = ASHMEM_NAME_DEF; struct file *vmfile; if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0') name = asma->name; //由linux提供的在tmpfs中创建一个临时文件 vmfile = shmem_file_setup(name, asma->size, vma->vm_flags); if (unlikely(IS_ERR(vmfile))) { ret = PTR_ERR(vmfile); goto out; } asma->file = vmfile; } get_file(asma->file); if (vma->vm_flags & VM_SHARED) shmem_set_file(vma, asma->file);//内存映射 else { if (vma->vm_file) fput(vma->vm_file); vma->vm_file = asma->file; } vma->vm_flags |= VM_CAN_NONLINEAR; out: mutex_unlock(&ashmem_mutex); return ret; } //清楚内存共享区 static int ashmem_release(struct inode *ignored, struct file *file) { struct ashmem_area *asma = file->private_data; struct ashmem_range *range, *next; mutex_lock(&ashmem_mutex); list_for_each_entry_safe(range, next, &asma->unpinned_list, unpinned) range_del(range); mutex_unlock(&ashmem_mutex); if (asma->file) fput(asma->file); kmem_cache_free(ashmem_area_cachep, asma); return 0; }
MemoryFile.java
public MemoryFile(String name, int length) throws IOException { mLength = length; mFD = native_open(name, length); ... } private static native FileDescriptor native_open(String name, int length) throws IOException;
android_os_MemoryFile.cpp
static jobject android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring name, jint length) { ... int result = ashmem_create_region(namestr, length); ... }
\system\core\libcutils\ashmem-dev.c
int ashmem_create_region(const char *name, size_t size) { int fd, ret; fd = open(ASHMEM_DEVICE, O_RDWR); if (fd < 0) return fd; if (name) { ... ret = ioctl(fd, ASHMEM_SET_NAME, buf); ... } ret = ioctl(fd, ASHMEM_SET_SIZE, size); ... return fd; error: close(fd); return ret; }
MemoryFile.java
public MemoryFile(String name, int length) throws IOException { ...... mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE); ...... }
android_os_MemoryFile.cpp
static jint android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jobject fileDescriptor, jint length, jint prot) { ... jint result = (jint)mmap(NULL, length, prot, MAP_SHARED, fd, 0); ... return result; }
未完。。。
相关文章推荐
- AndroidStudio开发环境搭建
- 带有服务器的Android公益活动平台源码
- 【Android杂谈】安卓开发模拟按键(一)
- Android 高手进阶
- androidstudio与gradle若干问题的几篇好文
- 如何在android style文件中使用自定义属性
- Android 多按钮监听器设置
- android优秀开源项目
- Android 添加联系人发短信以及打电话功能实现
- android 从零开始学新浪微博分享和第三方登陆(附源码下载)
- Android 点击按钮实现来回切换背景图和文字
- Android View滚动、拉伸到顶/底部弹性回弹复位
- Android中非常cool的API
- Android Volley框架的几种post提交请求方式(xml->xml json->json xml->json)
- Lichee(三) Android4.0该产品的目标文件夹,Lichee链接---extract-bsp
- android json解析使用总结(二)-—天气预报的实现
- Android中不同方向嵌套滑动的解决方案(ListView为例子)
- Android 创建AVD各参数详解
- android中MotionEvent.ACTION_CANCEL事件是什么意思,如何触发
- 菜鸟学习Android开发日志