您的位置:首页 > 移动开发 > Android开发

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;  
}


未完。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: