Android为每个应用分配多少内存?

2018-11-21 09:07:37
熟悉Android内存分配机制的朋友都知道,Android为每个进程分配内存时,采用弹性的分配方式,即刚开始并不会给应用分配很多的内存,而是给每一个进程分配一个“够用”的内存大小。

那Android到底为每个应用分配多少内存呢?我们可以实际测试一下:

以本人手上的努比亚NX510J手机为例:

    private void getMaxMemoryInfo(){
        Runtime rt = Runtime.getRuntime();
        long maxMemory = rt.maxMemory();
        Log.e("MaxMemory:", Long.toString(maxMemory/(1024*1024)));
        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        Log.e("MemoryClass:", Long.toString(activityManager.getMemoryClass()));
        Log.e("LargeMemoryClass:", Long.toString(activityManager.getLargeMemoryClass()));
    }

输出结果为:

06-06 15:27:22.740 11917-11917/com.suning.myapp E/MaxMemory:: 192
06-06 15:27:22.740 11917-11917/com.suning.myapp E/MemoryClass:: 192
06-06 15:27:22.740 11917-11917/com.suning.myapp E/LargeMemoryClass:: 512

把AndroidManifest.xml中的application标签加上

<application
        ...
        android:largeHeap="true"
        ...>
        ...
</application>

输出结果为:

06-06 15:32:06.168 21973-21973/com.suningtang.myapp E/MaxMemory:: 512
06-06 15:32:06.168 21973-21973/com.suningtang.myapp E/MemoryClass:: 192
06-06 15:32:06.168 21973-21973/com.suningtang.myapp E/LargeMemoryClass:: 512

可以看到,设置largeHeap为true时, 通过rt.maxMemory();获取的值为512M。

因此,对于本人这台手机,系统正常分配的内存最多为192M;当设置largeHeap时,最多可申请512M。当超过这个值时,就会出现OOM了。

这个值是在哪设置的呢?查看/system/build.prop文件内容:

shell@NX510J:/ $ cat /system/build.prop | grep heap
dalvik.vm.heapsize=36m
   
dalvik.vm.heapstartsize=8m    ----起始分配内存
dalvik.vm.heapgrowthlimit=192m ---- 一般情况app申请的最大内存 dalvik.vm.heapsize=512m   ---- 设置largeheap时,App可用的最大内存dalvik.vm.heaptargetutilization=0.75  ---- GC相关
dalvik.vm.heapminfree=512k
dalvik.vm.heapmaxfree=8m     ----- GC机制相关

上面的标注了各参数的含义。

那ActivityManager的getMemoryClass()和getLargeMemoryClass()方法返回的的是哪里的值呢?

//ActivityManager.java

public int getMemoryClass() {
        return staticGetMemoryClass();
    }
    
    /** @hide */
    static public int staticGetMemoryClass() {
       
        String vmHeapSize = SystemProperties.get("dalvik.vm.heapgrowthlimit", "");
        if (vmHeapSize != null && !"".equals(vmHeapSize)) {
            return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
        }
        return staticGetLargeMemoryClass();
    }
    
    /**
     * Return the approximate per-application memory class of the current
     * device when an application is running with a large heap.  This is the
     * space available for memory-intensive applications; most applications
     * should not need this amount of memory, and should instead stay with the
     * {@link #getMemoryClass()} limit.  The returned value is in megabytes.
     * This may be the same size as {@link #getMemoryClass()} on memory
     * constrained devices, or it may be significantly larger on devices with
     * a large amount of available RAM.
     *
     * <p>The is the size of the application's Dalvik heap if it has
     * specified <code>android:largeHeap="true"</code> in its manifest.
     */
    public int getLargeMemoryClass() {
        return staticGetLargeMemoryClass();
    }
    
    /** @hide */
    static public int staticGetLargeMemoryClass() {
        String vmHeapSize = SystemProperties.get("dalvik.vm.heapsize", "16m");
        return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length() - 1));
    }

上面的源码表明,getMemoryClass()和getLargeMemoryClass()方法最终读取的仍然是dalvik.vm.heapgrowthlimit和dalvik.vm.heapsize的值。而且,dalvik.vm.heapsize默认值为16M,这也是解释了google的原生OS默认值是16M了。而dalvik.vm.heapgrowthlimit和dalvik.vm.heapsize的值各个手机厂家的OS会对这个值进行修改,所以存在差异。

在App中获取内存信息

我们在应用中可以通过ActivityManager的MemoryInfo内部类获取内存信息,方法如下:

private void getMemoryInfo() {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();
    manager.getMemoryInfo(info);  
    Log.e("Memory","系统总内存:"+(info.totalMem / (1024*1024))+"M");
    Log.e("Memory","系统剩余内存:"+(info.availMem / (1024*1024))+"M");
    Log.e("Memory","系统是否处于低内存运行:"+info.lowMemory );
    Log.e("Memory","系统剩余内存低于"+( info.threshold  / (1024*1024))+"M时为低内存运行");
}




  • 2020-03-14 23:15:25

    icomoon使用详细介绍

    此篇博文讲述如何利用icomoon导入图标,从而把自己想要的都通过icomoon方式进行,大家都知道,网站以及移动端,用图标还是尽量选择这种。因为直接用image有些图标会失真,从而也是前端开发之中,需求去掌握的一项,很简单的就几个步骤。

  • 2020-03-14 23:39:59

    vuetify和@nuxt/vuetify icon 之我见

    vuetify中v-icon,貌似默认支持 Material Design Icons, Material Icons, Font Awesome 4 and Font Awesome 5, 我自己单独引入了vuetify 用哪一个图标都没有问题。但是用了@nuxt/vuetify只能用mdi-home这样的。不知道因为啥。肯定是封装后,封装成一个了。 但是我修改vuetify的设置,哪一个图标也都能用。哎,不过多研究了。

  • 2020-03-16 15:57:53

    nuxtjs中单独引入Message组件的问题

    // 引入elementUIimport { Message } from 'element-ui';//由于Message组件并没有install 方法供Vue来操作的,是直接返回的,因此按照官方文档单独引入的方法是//会报错的,需要给 Message 添加 install 方法Message.install = function (Vue, options) {Vue.prototype.$message = Message}Vue.use(Message )//消息提示

  • 2020-03-16 16:03:20

    css的var()函数

     随着sass,less预编译的流行,css也随即推出了变量定义var函数。var()函数,就如同sass和less等预编译软件一样,可以定义变量并且进行对应的使用。

  • 2020-03-16 16:52:05

    对icomoon的误解,以及最快速的使用

    此时需要注意顶部第一个选项,Quick Usage,一定要打开,Enable Quick Usage,谁让咱英语不好呢,这个时候会出现一个css连接,直接引用就好了,就可以随意使用图标了,引入这一个css就能实现我们的功能,省区引入太多文件的烦恼,你可以在浏览器打开这个css,可以看到里面把我们所用的文件整成base64了。所以挺好用的。

  • 2020-03-17 09:47:05

    video标签视频不自动播放的问题

    添加 muted 属性,就可以通过地址栏进入网页的时候自动播放了,手机端还是有的有限制的,比如iphone浏览器,就不行,苹果手机为了保护用户的流量和用户的意愿,是禁止自动播放的,必须有手动触发。

  • 2020-03-17 14:21:31

    nuxt+pm2 自动化部署及打包后文件自动上传阿里云 oss(精华)

    部署nuxtjs,这一篇文章就够了,pm2 代码自动发布依赖于 git 工具,先将 ssh 密钥配置再你的代码仓库(github 或者 gitLab),具体操作自行 google 或者点击github 配置 ssh。 使用 ssh 密钥链接服务器 s $ ssh-copy-id root@1.2.3.4 # 把本机的 SSH 秘钥添加至服务器,配置成功后,以后就不需要再执行这条 SSH 命令了