Android Dalvik虚拟机 对象创建内存分配流程
Posted baiiu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Dalvik虚拟机 对象创建内存分配流程相关的知识,希望对你有一定的参考价值。
前言
本篇文章介绍我们在日常开发使用Java时new对象的时,Dalvik在堆上的内存分配是如何分配的。内存又和gc相关,下篇文章会分析Dalvik的gc流程。
Dalvik内存管理
内存碎片问题其实是一个通用的问题,不单止Dalvik虚拟机在Java堆为对象分配内存时会遇到,C库的malloc函数在分配内存时也会遇到。android系统使用的C库bionic使用了Doug Lea写的dlmalloc内存分配器。也就是说,我们调用函数malloc的时候,使用的是dlmalloc内存分配器来分配内存。
Dalvik虚拟机的Java堆的底层实现是一块匿名共享内存,并且将其抽象为C库的一个mspace,即Dalvik虚拟机是利用的C库里面的dlmalloc内存分配器来解决内存碎片问题。
从Dailvk代码设计上存在两种内存限制,这两种限制在随着内存分配堆增长的过程中在不断调整,本篇文章分析内存分配流程,有机会分析内存管理这块,即Dalvik是如何调整堆的算法的,也比较复杂:
- 一是Dalvik设计的softLimit,即在Active堆中可以分配的内存上限;
- 二是mspace的hardLimit限制,即是匿名共享内存里的mspace_footprint限制;
对象创建内存分配流程
- Java中进行对象分配最终会通过tryMalloc进行内存分配
- tryMalloc操作的核心方法是dvmHeapSourceAlloc和dvmHeapSourceAllocAndGrow
- tryMalloc中,首次调用dvmHeapSourceAlloc进行分配,此时如果分配成功,超过concurrentStartBytes时则会触发concurrent gc,此为并发gc,较为轻量级
- dvmHeapSourceAlloc分配失败的原因可以是softlimit或mspace的footprint达到阈值
- 在首次执行dvmHeapSourceAlloc失败后触发GC_FOR_MALLOC进行同步内存回收,是stop world类型gc,最为耗时
- 如果此时还失败的话,会尝试调用dvmHeapSourceAllocAndGrow,先remove掉softLimt尝试分配,不行的话再把footprint增到最大再分配,分配完成后会将footprint还原
- 如果调用dvmHeapSourceAllocAndGrow仍然失败,那么会触发GC_BEFORE_OOM进行回收,这里传入参数true表示也要讲软引用一块清除掉了
- 软引用清除掉后之后再会尝试dvmHeapSourceAllocAndGrow,如果还是失败,那么会抛出OutOfMemoryError错误
Heap.cpp
dvmMalloc
Java的动态内存分配是通过new操作符完成的,而最终调用的是dvmMalloc()函数,Dalvik在内存分配上也在尽力分配出内存,直到最后OOM。
// Allocate storage on the GC heap. We guarantee 8-byte alignment.
void* dvmMalloc(size_t size, int flags)
void *ptr;
dvmLockHeap();
// Try as hard as possible to allocate some memory.
ptr = tryMalloc(size);
dvmUnlockHeap();
if (ptr != NULL)
// track it,此处在下篇文章分析,这里可以dump出来分配的内存和堆栈
if ((flags & ALLOC_DONT_TRACK) == 0)
dvmAddTrackedAlloc((Object*)ptr, NULL);
else
// The allocation failed; throw an OutOfMemoryError.
throwOOME();
return ptr;
tryMalloc
// Try as hard as possible to allocate some memory.
static void *tryMalloc(size_t size)
void *ptr;
ptr = dvmHeapSourceAlloc(size);
if (ptr != NULL)
return ptr;
// The allocation failed. If the GC is running, block until it completes and retry.
if (gDvm.gcHeap->gcRunning)
// The GC is concurrently tracing the heap. Release the heap lock, wait for the GC to complete, and retrying allocating.
dvmWaitForConcurrentGcToComplete();
else
// Try a foreground GC since a concurrent GC is not currently running.
gcForMalloc(false);
ptr = dvmHeapSourceAlloc(size);
if (ptr != NULL)
return ptr;
// Even that didn't work; this is an exceptional state. Try harder, growing the heap if necessary.
ptr = dvmHeapSourceAllocAndGrow(size);
if (ptr != NULL)
// may want to grow a little bit more so that the amount of free space is equal to the old free space + the utilization slop for the new allocation.
size_t newHeapSize;
newHeapSize = dvmHeapSourceGetIdealFootprint();
return ptr;
/* Most allocations should have succeeded by now, so the heap
* is really full, really fragmented, or the requested size is
* really big. Do another GC, collecting SoftReferences this
* time. The VM spec requires that all SoftReferences have
* been collected and cleared before throwing an OOME.
*/
gcForMalloc(true);
ptr = dvmHeapSourceAllocAndGrow(size);
if (ptr != NULL)
return ptr;
dvmDumpThread(dvmThreadSelf(), false);
return NULL;
HeapSouce.cpp
dvmHeapSourceAlloc
// Allocates <n> bytes of zeroed data.
void* dvmHeapSourceAlloc(size_t n)
HeapSource *hs = gHs;
Heap* heap = hs2heap(hs);
if (heap->bytesAllocated + n > hs->softLimit)
// softLimit限制;This allocation would push us over the soft limit; act as if the heap is full.
return NULL;
void* ptr = mspace_calloc(heap->msp, 1, n);
if (ptr == NULL)
// hardLimit限制
return NULL;
countAllocation(heap, ptr);
// Check to see if a concurrent GC should be initiated. The garbage collector thread is already running or has yet to be started. Do nothing.
if (gDvm.gcHeap->gcRunning || !hs->hasGcThread)
return ptr;
// 唤醒concurrent gc. We have exceeded the allocation threshold. Wake up the garbage collector.
if (heap->bytesAllocated > heap->concurrentStartBytes)
dvmSignalCond(&gHs->gcThreadCond);
return ptr;
dvmHeapSourceAllocAndGrow
// Allocates <n> bytes of zeroed data, growing as much as possible if necessary.
void* dvmHeapSourceAllocAndGrow(size_t n)
HeapSource *hs = gHs;
Heap* heap = hs2heap(hs);
void* ptr = dvmHeapSourceAlloc(n);
if (ptr != NULL)
return ptr;
size_t oldIdealSize = hs->idealSize;
// We're soft-limited. Try removing the soft limit to see if we can allocate without actually growing.
if (isSoftLimited(hs))
hs->softLimit = SIZE_MAX;
ptr = dvmHeapSourceAlloc(n);
if (ptr != NULL)
snapIdealFootprint();
return ptr;
// We're not soft-limited. Grow the heap to satisfy the request. If this call fails, no footprints will have changed.
ptr = heapAllocAndGrow(hs, heap, n);
if (ptr != NULL)
snapIdealFootprint();
else
setIdealFootprint(oldIdealSize);
return ptr;
// Remove any hard limits, try to allocate, and shrink back down. Last resort when trying to allocate an object.
static void* heapAllocAndGrow(HeapSource *hs, Heap *heap, size_t n)
// Grow as much as possible, but don't let the real footprint go over the absolute max.
size_t max = heap->maximumSize;
mspace_set_footprint_limit(heap->msp, max);
void* ptr = dvmHeapSourceAlloc(n);
// Shrink back down as small as possible. Our caller may readjust max_allowed to a more appropriate value.
mspace_set_footprint_limit(heap->msp, mspace_footprint(heap->msp));
return ptr;
以上是关于Android Dalvik虚拟机 对象创建内存分配流程的主要内容,如果未能解决你的问题,请参考以下文章