Android中App可分配内存的大小

2018-11-17 21:11:14

参考地址   Android中App可分配内存的大小


现在真实测试结果:  

1,为了搞清楚每个应用程序在Android系统中最多可分配多少内存空间,我们使用了真机进行测试,测试机型为魅族MX4 Pro,3G内存。

测试方法是直接申请一块较大的内存空间,看应用程序在最多申请多大的内存空间时会崩溃。

  结果:(1)未设定属性android:largeheap = "true"时,可以申请到的最大内存空间为221M。

     (2)设定属性android:largeheap = "true"时, 可以申请的最大内存空间为478M,是原来的两倍多一些。

  网上有网友提出可申请到的最大内存空间与手机配置有关,以后会加以验证。

 

 

2.实测,不准确, 准确的说话是 google原生OS的默认值是16M,但是各个厂家的OS会对这个值进行修改。

比如本人小米2S为例,这个值应该是96M。

 

Runtime rt=Runtime.getRuntime();
long maxMemory=rt.maxMemory();
log.i("maxMemory:",Long.toString(maxMemory/(1024*1024)));
這個可以直接得到app可使用的最大memory size算出來是MB, 获得的是heapgrowthlimit


先看机器的内存限制,在/system/build.prop文件中:
heapgrowthlimit就是一个普通应用的内存限制,用ActivityManager.getLargeMemoryClass()获得的值就是这个。
而heapsize是在manifest中设置了largeHeap=true 之后,可以使用的最大内存值
结论就是,设置largeHeap的确可以增加内存的申请量。但不是系统有多少内存就可以申请多少,而是由dalvik.vm.heapsize限制。
你可以在app manifest.xml加 largetHeap=true
可以申請較多的記憶體 ,但還是有機會爆掉.

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


cat /system/build.prop   //读取这些值
getprop dalvik.vm.heapsize  //如果build.prop里面没有heapsize这些值,可以用这个抓取默认值
setprop dalvik.vm.heapsize 256m  //设置

-----------------------    build.prop 部分内容 ---------------------

dalvik.vm.heapstartsize=8m
dalvik.vm.heapgrowthlimit=96m
dalvik.vm.heapsize=384m
dalvik.vm.heaputilization=0.25
dalvik.vm.heapidealfree=8388608
dalvik.vm.heapconcurrentstart=2097152
ro.setupwizard.mode=OPTIONAL
ro.com.google.gmsversion=4.1_r6
net.bt.name=Android
dalvik.vm.stack-trace-file=/data/anr/traces.txt

 

 

最早的说法:

1、APP默认分配内存大小

在Android里,程序内存被分为2部分:native和dalvik,dalvik就是我们普通的Java使用内存,也就是我们上一篇文章分析堆栈的时候使用的内存。我们创建的对象是在这里面分配的,对于内存的限制是 native+dalvik 不能超过最大限制。android程序内存一般限制在16M,也有的是24M(早期的Android系统G1,就是只有16M)。具体看定制系统的设置,在Linux初始化代码里面Init.c,可以查到到默认的内存大小。有兴趣的朋友,可以分析一下虚拟机启动相关代码。这块比较深入,目前我也没时间去分析,后面有空会去钻研一下。

  gDvm.heapSizeStart = 2 * 1024 * 1024;   // heap初始化大小为2M
  gDvm.heapSizeMax = 16 * 1024 * 1024;    // 最大的heap为16M 
  

  2、Android的GC如何回收内存

Android的一个应用程序的内存泄露对别的应用程序影响不大。为了能够使得Android应用程序安全且快速的运行,Android的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进程中运行的。Android为不同类型的进程分配了不同的内存使用上限,如果程序在运行过程中出现了内存泄漏的而造成应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被kill掉,这使得仅仅自己的进程被kill掉,而不会影响其他进程(如果是system_process等系统进程出问题的话,则会引起系统重启)。

做应用开发的时候,你需要了解系统的GC(垃圾回收)机制是如何运行的,Android里面使用有向图作为遍历回收内存的机制。Java将引用关系考虑为图的有向边,有向边从引用者指向引用对象。线程对象可以作为有向图的起始顶点,该图就是从起始顶点开始的一棵树,根顶点可以到达的对象都是有效对象,GC不会回收这些对象。如果某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象不再被引用,可以被GC回收。

  因此对于我们已经不需要使用的对象,我们可以把它设置为null,这样当GC运行的时候,就好遍历到你这个对象已经没有引用,会自动把该对象占用的内存回收。我们没法像C++那样马上释放不需要的内存,但是我们可以主动告诉系统,哪些内存可以回收了。

  3、查看应用内存使用情况

  下面我们看看如何在开发过程中查看我们程序运行时内存使用情况。我们可以通过ADB的一个命令查看:

  //$package_name:应用包名
  //$pid:应用进程ID,可以用PS命令查看
  adb shell dumpsys meminfo $package_name or $pid 

  

  上面是我使用包名查看Gallery例子的内存使用情况图,里面信息很多,不过我们主要关注的是native和Davilk的使用情况。(Android2.X和Android4.X查看的信息排序是不一样的,内容差不多,不过排布有差异,我上面是4.0的截图)

Android底层内核是基于Linux的,而Linux里面相对Window来说,有一点很特别的是,会尽量使用系统内存加载一些缓存数据或者进程间共享数据。Linux本着不用白不用的原则,会尽量使用系统内存,加快我们应用的运行速度。当然,如果我们期待某个需要大内存的应用,系统也能马上释放出一定的内存使用,这是系统内部调度实现。因此严格来说,我们要准备计算Linux下某个进程内存大小比较困难。 因为有paging out to disk(换页),所以如果你把所有映射到进程的内存相加,它可能大于你的内存的实际物理大小。


  dalvik:是指dalvik所使用的内存。 
  native:是被native堆使用的内存。应该指使用C\C++在堆上分配的内存。 
  other:是指除dalvik和native使用的内存。但是具体是指什么呢?至少包括在C\C++分配的非堆内存,比如分配在栈上的内存。puzlle! 
  Pss:它是把共享内存根据一定比例分摊到共享它的各个进程来计算所得到进程使用内存。网上又说是比例分配共享库占用的内存,也就是上面所说的进程共享问题。 
  PrivateDirty:它是指非共享的,又不能换页出去(can not be paged to disk )的内存的大小。比如Linux为了提高分配内存速度而缓冲的小对象,即使你的进程结束,该内存也不会释放掉,它只是又重新回到缓冲中而已。 
  SharedDirty:参照PrivateDirty我认为它应该是指共享的,又不能换页出去(can not be paged to disk )的内存的大小。比如Linux为了提高分配内存速度而缓冲的小对象,即使所有共享它的进程结束,该内存也不会释放掉,它只是又重新回到缓冲中而已。

  上面针对meminfo里面的信息给出解析,这些很多我是参考了网上一些文章,所以如果有理解不到位的,欢迎各位指出。

  4、程序中获取内存信息

  通过ActivityManager获取相关信息,下面是一个例子代码:

  privatevoid displayBriefMemory()  
  {     
      final ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);     
      ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();    
      activityManager.getMemoryInfo(info);     
      Log.i(tag,"系统剩余内存:"+(info.availMem >> 10)+"k");    
      Log.i(tag,"系统是否处于低内存运行:"+info.lowMemory); 
      Log.i(tag,"当系统剩余内存低于"+info.threshold+"时就看成低内存运行"); 
  } 

  另外通过Debug的getMemoryInfo(Debug.MemoryInfo memoryInfo)可以得到更加详细的信息。跟我们在ADB Shell看到的信息一样比较详细。

  5、总结

今天主要是分析了如何获取我们应用的内存使用情况信息,关于这方面的信息,其实还有其他一些方法。另外还介绍APP应用的默认内存已经Android的GC回收,不过上面只是很浅薄地分析了一下,让大家有个印象。这些东西真要深入分析得花不少精力。因为我们的目的只是解决OOM问题,所以目前没打算深入分析,后面有时间进行Android系统分析的时候,我们再深入分析。下一次我们用以前写的Gallery例子讲解如何避免OOM问题,以及内存优化方法。

 

总述

Android应用程序被限制了内存使用上限,一般为16M或24M(具体看系统设置),当应用的使用内存超过这个上限时,就会被系统认为内存泄漏,被kill掉。

  • 2020-11-17 10:05:53

    mongoDB 修改密码

    mongodb的用户信息是存放在system.users表中的,修改密码不能直接更新表数据,这样的话,存到表里的密码是明文的,这就不对了。

  • 2020-11-17 10:13:16

    Vue.observable()进行状态管理

    随着组件的细化,就会遇到多组件状态共享的情况, Vuex当然可以解决这类问题,不过就像 Vuex官方文档所说的,如果应用不够大,为避免代码繁琐冗余,最好不要使用它,今天我们介绍的是 vue.js 2.6 新增加的 Observable API ,通过使用这个 api 我们可以应对一些简单的跨组件数据状态共享的情况。

  • 2020-11-17 10:17:18

    MongoDB日志文件查看

    默认情况下,MongoDB在此路径/var/log/mongodb/mongodb.log创建日志文件,如果找不到该日志文件,请检查MongoDB配置文件。

  • 2020-11-17 11:57:16

    app抓包无数据

    我们经常在wifi设置中 设置代理到我们的pc http代理软件上,多数情况下,此时我们开启的app流量都可以在代理软件上看到,比如charles , fiddler等等。 但是细心的人会发现 某些大厂的app 某些请求 在这些 http代理软件上就是抓不到, 给人的感觉就是 流量没从代理软件走一样。

  • 2020-11-17 11:57:55

    app抓不到包,解决很简单

    1.手机安装virtualXpost 并激活xpost 框架,如有问题自行百度。 2.安装justTrustMe,然后再virtualXpost中添加此模块 3.安装手机抓包神器packet capture 4.在virtualXpost中运行app,并打开packet capture抓包就行

  • 2020-11-17 16:50:16

    JS常见加密混淆方式

    目录 前端js常见混淆加密保护方式 eval方法等字符串参数 emscripten WebAssembly js混淆实现 JSFuck AAEncode JJEncode 代码压缩 变量名混淆 字符串混淆 自我保护,比如卡死浏览器 控制流平坦化 僵尸代码注入 对象键名替换 禁用控制台输出 调试保护,比如无限Debug,定时Debug 域名锁定