135

ART GC &APP memory

 5 years ago
source link: http://www.10tiao.com/html/431/201806/2650237000/1.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Android  ART 虚拟机分配及GC

[dalvik.vm.heapgrowthlimit]: [192m]

[dalvik.vm.heapmaxfree]: [8m]

 [dalvik.vm.heapminfree]: [512k]

[dalvik.vm.heapsize]: [512m]

[dalvik.vm.heapstartsize]: [8m]

[dalvik.vm.heaptargetutilization]: [0.75]



  • dalvik.vm.heapgrowthlimit和dalvik.vm.heapsize都是java虚拟机的最大内存限制,一般heapgrowthlimit< heapsize,如果在Manifest中的application标签中声明android:largeHeap=“true”,APP直到heapsize才OOM,否则达到heapgrowthlimit就OOM

  • dalvik.vm.heapstartsize Java堆的起始大小,指定了Davlik虚拟机在启动的时候向系统申请的物理内存的大小,后面再根据需要逐渐向系统申请更多的物理内存,直到达到MAX

  • dalvik.vm.heapminfree 堆最小空闲值,GC后

  • dalvik.vm.heapmaxfree堆最大空闲值

  • dalvik.vm.heaptargetutilization 堆目标利用率

后面三个值用来确保每次GC之后Java堆已经使用和空闲的内存有一个合适的比例,这样可以尽量地减少GC的次数,堆的利用率为U,最小空闲值为MinFree字节,最大空闲值为MaxFree字节,假设在某一次GC之后,存活对象占用内存的大小为LiveSize。那么这时候堆的理想大小应该为(LiveSize / U)。但是(LiveSize / U)必须大于等于(LiveSize + MinFree)并且小于等于(LiveSize + MaxFree),否则,就要进行调整,调整的其实是软上限softLimit,


二、ART GC何时用到这三个值

首先从ART的GC流程中找出用到这三个值的地方。

ART分配对象失败或者已使用内存超过某个设定的阈值就会触发垃圾回收(GC),GC时调用的接口函数是CollectGarbageInternal,此方法的实现如下所示:


collector::GcType Heap::CollectGarbageInternal(…) {

  …

  collector->Run(gc_cause, clear_soft_references || runtime->IsZygote());//执行GC

  …

 

RequestTrim(self);//裁剪堆

  reference_processor_.EnqueueClearedReferences(self);// 将被回收了的引用对象添加到各自关联的队列中

  GrowForUtilization(collector);//调整堆的大小

  …

}


enum GcType { // Placeholder for when no GC has been performed.

kGcTypeNone,
// Sticky mark bits GC that attempts to only free objects allocated since the last GC.

kGcTypeSticky,
// Partial GC that marks the application heap but not the Zygote.

kGcTypePartial,
 // Full GC that marks and frees in both the application and Zygote heap.

kGcTypeFull,
  // Number of different GC types.

kGcTypeMax,
};

此方法首先会根据选定的垃圾回收算法执行一次垃圾回收,通常的设置是前台垃圾回收(Foreground GC)执行的是并发标记清除算法(CMS),后台垃圾回收(Background GC)执行的是Compacting GC,在GC执行完成之后,就进入了垃圾回收收尾阶段,此阶段主要完成如下三件事:


(1)RequestTrim()对堆进行裁剪


GC回收垃圾完成之后需要决定是否要对堆进行裁剪,也就是将空闲内存临时归还给操作系统。此操作会对堆进行一次裁剪操作,而裁剪一个堆空间时会先锁住这个堆然后才能执行扫描操作,这会造成一点卡顿。谷歌目前对于何时进行堆裁剪的设定如下:如果5秒内没有任何堆裁剪发生过,那么此次GC之后就得进行一次堆裁剪。这个简单的设定防止了堆裁剪的过于频繁。


(2)EnqueueClearedReferences()处理被回收了的引用对象


调用函数EnqueueClearedReferences将目标对象已经被回收了的引用对象添加到各自关联的队列中去,以便应用程序可以知道它们的目标对象已经被回收了。


(3)GrowForUtilization()调整堆的大小


调用函数GrowForUtilization根据预先设置的堆目标利率以及最小和最大空闲内存数调整预留空闲内存大小,同时也会重新设置下次的GC策略以及并发垃圾回收的触发阈值。


综上,堆利用率heaptargetutilization、堆最小空闲内存heapminfree和堆最大空闲内存heapmaxfree这三个值在GrowForUtilization()中使用,用来调整GC后堆的大小。


三、这三个属性值的作用


GC触发后,垃圾回收器回收了应用不再使用的垃圾对象,这样应用的空闲内存就可能很大或者由于回收垃圾不够多导致空闲内存还是很小。如果此空闲内存很大,Android系统出于提高内存利用率的考虑是不会把这么大一块内存都给应用程序的,它会根据应用预先设定的堆利用率(heaptargetutilization)、最大和最小空闲内存数(heapmaxfree、heapminfree)等参数来调整此空闲内存的大小;如果此空闲内存很小,那么势必此空闲内存将很快分配光,下次GC会来的很快,所以遇到这种情况,ART会扩大此空闲内存的大小。

堆利用率(heaptargetutilization)、最大空闲内存(heapmaxfree)和最小空闲内存(heapminfree)在代码里的变量名为:utilization,max_free_,min_free_。

我们知道 ART中有三种GC策略:

i)Sticky GC:分代GC,只回收上次GC后分配的对象

ii)Partial GC:局部GC,不回收zygote堆

iii)Full GC:全局GC

当前GC使用哪种GC策略ART有一套判断的标准,总的来说,Sticky GC可能性最大,Full GC可能性最小。

对于不同的GC策略,预留空闲内存有不同的计算方法。


(1)如果GC策略是局部垃圾回收(Partial GC)或者全局垃圾回收(Full GC),那么预留空闲内存的计算方法如下所示:


const float multiplier = HeapGrowthMultiplier();//获取堆扩展系数

intptr_t delta = bytes_allocated / GetTargetHeapUtilization() - bytes_allocated;//由堆利用率算出所需空闲内存

target_size = bytes_allocated + delta * multiplier;//由堆利用率决定的最终堆大小

target_size = std::min(target_size, bytes_allocated + 

static_cast<uint64_t>(max_free_ * multiplier));//考虑最大空闲内存后的最终堆大小

target_size = std::max(target_size, bytes_allocated + 

static_cast<uint64_t>(min_free_ * multiplier));//考虑最小空闲内存后的最终堆大小


此计算方法首先会获取一个堆扩展系数,它是根据前后台GC来区分的,一般前台GC此系数是2,也就是把空闲内存扩大2倍,后台GC此系数是1。因为对于前台GC来说,此时应用程序是运行在前台的,如果堆扩展较小,那么空闲内存就会更快的用光,也就是说下次GC来的更快,而GC会给应用造成短时间的暂停,影响应用的性能,所以说为了使前台应用有更好的性能,ART运行时会给前台应用更多的堆空闲空间。


然后由堆利用率(utilization)算出理论上所需的空闲内存,堆利用率按照谷歌的推荐一般设为0.75。此时算出来的堆大小还不是最终结果,还需考虑另外两个限制值:最小空闲内存(min_free_)和最大空闲内存(max_free_)。也就是需要把预留空闲内存控制在两倍的最小空闲内存和两倍的最大空闲内存之间。这样获得的target_size才是堆的最终大小,也就是已分配对象的大小和预留空闲内存之和。对于Partial GC和Full GC,预留空闲内存的大小和已分配对象的大小的关系如下:



更直观点画个图:



(2) 如果GC策略是分代垃圾回收(Sticky GC),也就是只回收上次GC后分配的对象,那么预留空闲内存的大小按如下方式计算:


if (bytes_allocated + max_free_ < max_allowed_footprint_) {

   target_size = bytes_allocated + max_free_;

} else {

   target_size = std::max(bytes_allocated, static_cast<uint64_t>(max_allowed_footprint_));


max_allowed_footprint_是堆增长的上限值,上述计算方法就是在堆空间允许的范围内,尽量使预留空闲内存为最大空闲内存(max_free_),而与已使用内存的多少无关,如下图:




综上,堆利用率heaptargetutilization、堆最小空闲内存heapminfree和堆最大空闲内存heapmaxfree这三个值是用来调整GC后堆的空闲内存大小的,并且对于不同的GC策略有不同的调整方法,如图所示,从而使GC后堆的空闲内存不至于太大或者太小,太大则浪费内存,太小则会导致GC触发次数增多。


四、通过属性值对ART GC调优

从图看出,

(a)当前使用Sticky GC则预留空闲内存为heapmaxfree;

(b)当前使用非Sticky GC则预留空闲内存在2*heapminfree到2*heapmaxfree之间变动,utilization决定转折点,即(ub/(1-u),2b)和(ua/(1-u),2a),一般utilization都默认设为0.75,所以当应用已使用内存超过3a即3*heapmaxfree后,预留空闲内存恒定为3*heapmaxfree


从上面的分析可以看出,属性值heapmaxfree、heapminfree、heaptargetutilization对ART GC的性能影响如下,

i)heapmaxfree:当应用使用内存超过3*heapmaxfree后,预留空闲内存恒为2*heapmaxfree,所以heapmaxfree越小,2*heapmaxfree大小的空闲内存就会越快用光,GC就会触发的越频繁。增大heapmaxfree可以使应用的GC频率降低,但会使应用的内存占用变大。

ii)heapminfree:当应用使用内存小于3*heapminfree时,预留空闲内存设为2*heapminfree,一般来说应用在启动时占用内存才会这么小。

iii)heaptargetutilization:影响不大,一般都默认设为0.75。


综上,三个属性值heapmaxfree、heapminfree、heaptargetutilization中,相比较而言,heapmaxfree对GC调优效果最好,能影响GC触发的频率,对GC执行时间、GC暂停时间、GC吞吐量等关键GC性能指标的影响很小。

对于内存2-3GB的手机,heapmaxfree一般设为8MB,如果GC触发比较频繁,则可以把heapmaxfree设的大一点。



优化app memory 也可以修改这几个值。


minfree 为512k


                 Pss  Private  Private  SwapPss     Heap     Heap     Heap

                 Total    Dirty    Clean    Dirty     Size    Alloc     Free

                ------   ------   ------   ------   ------   ------   ------

  Native Heap     4332     4272        0        0    12288     8403     3884

  Dalvik Heap     1140     1104        0        0     2905     1369     1536

 Dalvik Other      548      548        0        0                           

        Stack       92       92        0        0                           

       Ashmem        2        0        0        0                           

      Gfx dev     2560     1100     1460        0                           

    Other dev        8        0        8        0                           

     .so mmap     1678      152      152        0                           

    .apk mmap      345        0       36        0                           

    .ttf mmap       51        0        0        0                           

    .dex mmap     4231        4     3104        0                           

    .oat mmap       75        0        4        0                           

    .art mmap     4086     3832       64        0                           

   Other mmap        7        4        0        0                           

   EGL mtrack    29600    29600        0        0                           

    GL mtrack     6676     6676        0        0                           

      Unknown      603      548        0        0                           

        TOTAL    56034    47932     4828        0    15193     9772     5420

 

 App Summary

                       Pss(KB)

                        ------

           Java Heap:     5000

         Native Heap:     4272

                Code:     3452

               Stack:       92

            Graphics:    38836

       Private Other:     1108

              System:     3274

 

               TOTAL:    56034       TOTAL SWAP PSS:        0

 

 Objects

               Views:       19         ViewRootImpl:        1

         AppContexts:        3           Activities:        1

              Assets:        2        AssetManagers:        3

       Local Binders:        8        Proxy Binders:       15

       Parcel memory:        2         Parcel count:       10

    Death Recipients:        0      OpenSSL Sockets:        0

            WebViews:        0

 

 SQL

         MEMORY_USED:        0

  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

 


minfree 为6m

                   Pss  Private  Private  SwapPss     Heap     Heap     Heap

                 Total    Dirty    Clean    Dirty     Size    Alloc     Free

                ------   ------   ------   ------   ------   ------   ------

  Native Heap     4320     4256        0        0    12288     8473     3814

  Dalvik Heap     1507     1116        0        0    19801     1369    18432

 Dalvik Other      648      632        0        0                           

        Stack       92       92        0        0                           

       Ashmem        2        0        0        0                           

      Gfx dev     2560     1896      664        0                           

    Other dev        8        0        8        0                           

     .so mmap     1628      152      152        0                           

    .apk mmap      300        0       36        0                           

    .ttf mmap       51        0        0        0                           

    .dex mmap     4154        4     3096        0                           

    .oat mmap       73        0        4        0                           

    .art mmap     4042     3824       68        0                           

   Other mmap        8        4        0        0                           

   EGL mtrack    29600    29600        0        0                           

    GL mtrack     6676     6676        0        0                           

      Unknown      621      568        0        0                           

        TOTAL    56290    48820     4028        0    32089     9842    22246

 

 App Summary

                       Pss(KB)

                        ------

           Java Heap:     5008

         Native Heap:     4256

                Code:     3444

               Stack:       92

            Graphics:    38836

       Private Other:     1212

              System:     3442

 

               TOTAL:    56290       TOTAL SWAP PSS:        0

 

 Objects

               Views:       19         ViewRootImpl:        1

         AppContexts:        3           Activities:        1

              Assets:        2        AssetManagers:        3

       Local Binders:        8        Proxy Binders:       15

       Parcel memory:        3         Parcel count:       12

    Death Recipients:        0      OpenSSL Sockets:        0

            WebViews:        0

 

 SQL

         MEMORY_USED:        0

  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0




About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK