200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > ART运行时垃圾收集机制简要介绍和学习计划

ART运行时垃圾收集机制简要介绍和学习计划

时间:2020-06-02 20:57:59

相关推荐

ART运行时垃圾收集机制简要介绍和学习计划

1.ART运行时堆的创建过程。

2.ART运行时的对象分配过程。

3.ART运行时的垃圾收集过程。

MarkSweep*

Zygote Active堆、Card Table、Heap

ART

HeapBitmap MarSta

art@classes dex中,以后只要系统启动类路径中的DEX文件不发生变化(即不发生更新升级),那么以后每次系统启动只需要将文件system@framework@boot

boot oat文件。再接下来就是Zygote

Header中。此外,system@framework@boot

dex中,以后只要系统启动类路径中的DEX文件不发生变化(即不发生更新升级),那么以后每次系统启动只需要将文件system@framework@boot

oat文件。再接下来就是Zygote

ImageSpace就将内部的live_bitmap_同时作为Live

ART

Zygote Space Allocation Space

Dalvik和ART运行时环境的区别_ Zygote Active堆、Card

Heap

CollectGarbage System.gc/collector/gc_type

ConcurrentGC GC

CollectGarbageInternal // ART

MarkSweep*

PartialMarkSweep和StickyMarkSweep三种类型的垃圾收集器组成。它们的类关系如图4所示:

1. GetBytesAllocated: 获得当前已经分配的字节数。

2. GetObjectsAllocated: 获得当前已经分配的对象数。

3. GetTotalBytesAllocated: 获得Space自创建以来所分配的字节数。

4. GetTotalObjectsAllocated: 获得Space自创建以来所分配的对象数。

5. Alloc: 在Space上分配一个指定大小的对象。

6. AllocationSize: 获得一个对象占据的内存块大小。

7. Free: 释放一个对象占据的内存块。

8. FreeList: 批量释放一系列对象占据的内存块。

ART运行时垃圾收集机制简要介绍和学习计划

GetLiveObjects GetMarkObjects

Image Space boot Zygote Space Allocation Space LargeObjectMapSpace描述的是Large

CardTable Live Object Bitmap。

Live Bitmap。 Mark Object Bitmap。

Mark Bitmap。

Mark Live Allocation Stack等概念,如图1所示:

mirror

1. Create: 一个静态成员函数,用来创建一个LargeObjectMapSpace。

2. Alloc: 重写了父类AllocSpace的成员函数Alloc。

3. AllocationSize: 重写了父类AllocSpace的成员函数AllocationSize。

4. Free: 重写了父类AllocSpace的成员函数Free。

ModUnionTable CardTable

除了Garbage Collector和Space,ART运行时垃圾收集机制比Dalvik垃圾收集机制还多了一个称Mod Union Table的概念。Mod Union Table是与Card Table配合使用的,用来记录在一次GC过程中,记录不会被回收的Space的对象对会被回收的Space的引用。例如,Image Space的对象对Zygote Space和Allocation Space的对象的引用,以及Zygote Space的对象对Allocation Space的对象的引用

Runtime Init

live-bitmap.reset HeapBitmap

mark-bitmap.reset HeapBitmap

ljkkjkkh

Image Space -》 Mod Union Table3)Heap

为default_mark_stack_size,即64KB

max

system@framework@boot.art@classes.dex中,以后只要系统启动类路径中的DEX文件不发生变化(即不发生更新升级),那么以后每次系统启动只需要将文件system@framework@boot

/data/dalvik-cache目录下是否存在一个system@framework@boot

ImageSpace

callee_save_method ArtMethod*

space->oat_file_.reset

space->oat_file_.recent_free_pos_

ArtMethod*

CreateFromMemMap CreateMallocSpace

live-bitmap mark-bitmap

Allocation Space

void Heap::MarkAllocStack(accounting::SpaceBitmap* bitmap, accounting::SpaceSetMap* large_objects,

accounting::ObjectStack* stack) {

mirror::Object** limit = stack->End();

for (mirror::Object** it = stack->Begin(); it != limit; ++it) {

const mirror::Object* obj = *it;

DCHECK(obj != NULL);

if (LIKELY(bitmap->HasAddress(obj))) {

bitmap->Set(obj);

} else {

large_objects->Set(obj);

}

}

}

mirror::Object**

AllocObj mirror

Zygote Space Allolication Space large_object_space

IsOutOf

kGcTypeFull

kGcTypeSticky kGcTypePartial Allocation

For Alloc Background

InitializePhase

SuspendAll Thread

Mark Phantom

CollectGarbageInternal

gc_complete_cond_->Broadcast self

mark_sweep

kGcTypeSticky、kGcTypePartial和kGcTypeFull的垃垃圾收集器组成

MarkSweep类用来回收Zygote Space和Allocation Space的垃圾,PartialMarkSweep类用来回收Allocation Space的垃圾,StickyMarkSweep类用来回收上次GC以来在Allcation Space上分配的最终又没有被引用的垃圾。

MarkSweep Zygote Allocation

ParallelGCThreads指定。

StickyMarkSweep

ART运行时提供给由DEX字节码翻译而来的本地机器代码使用的一个函数表中,包含了一个pCheckSuspend函数指针,

DeX 字节码

WaitForConcurrentGcToComplete

Wait

cond_is notified

TransitionFromRunnableToSuspended

TransitionFromSuspendedToRunnable

kGcRetentionPolicyAlwaysCollect

Allocation

current_mark_bitmap_

Default Mark Bitmaps

kGcRetentionPolicyAlwaysCollect Space

Mark Bitmap4)Mark

Mark Sweep ParallelGCThreads指定。

Zygote Allocation

Sticky

Handle Dirty Object阶段

Heap类的成员函数ProcessCards用来处理Card Table里面的Dirty Card,它是在Marking阶段被调用的

while (word_cur < word_end) {

while ((expected_word = *word_cur) != 0) {

new_word =

(visitor((expected_word >> 0) & 0xFF) << 0) |

(visitor((expected_word >> 8) & 0xFF) << 8) |

(visitor((expected_word >> 16) & 0xFF) << 16) |

(visitor((expected_word >> 24) & 0xFF) << 24);

if (new_word == expected_word) {

// No need to do a cas.

break;

}

if (LIKELY(android_atomic_cas(expected_word, new_word,

reinterpret_cast<int32_t*>(word_cur)) == 0)) {

for (size_t i = 0; i < sizeof(uintptr_t); ++i) {

const byte expected_byte = (expected_word >> (8 * i)) & 0xFF;

const byte new_byte = (new_word >> (8 * i)) & 0xFF;

if (expected_byte != new_byte) {

modified(reinterpret_cast<byte*>(word_cur) + i, expected_byte, new_byte);

}

}

break;

}

}

++word_cur;

}

uintptr_t

expected_word >>

它是一个能够存储指针的无符号int。这通常意味着它与指针的大小相同。

if (LIKELY(android_atomic_cas(expected_word, new_word,

reinterpret_cast<int32_t*>(word_cur)) == 0)) {

for (size_t i = 0; i < sizeof(uintptr_t); ++i) {

const byte expected_byte = (expected_word >> (8 * i)) & 0xFF;

const byte new_byte = (new_word >> (8 * i)) & 0xFF;

if (expected_byte != new_byte) {

modified(reinterpret_cast<byte*>(word_cur) + i, expected_byte, new_byte);

i 为第几个字节

4字节对齐 4字节为边界

%N == 0

ContinousSpace * s31寄存器的ART方法,即由被调用者保存非参数使用的通用寄存器以及所有的浮点数寄存器。

ModUnionClearCardSetVisitor

MarkReferences

VisitConcurrentRoots Dex Cache。关于Dex

mutator_lock_

MarkSweep

checkpoint_function-

VisitRoots MarkSweep

Mark Sweep也不会对上次GC以后分配的对象进行垃圾回收。由于Sticky Mark Sweep刚好相反,它要对上次GC以后分配的对象进行垃圾回收,因此,它就必须要重写MarkSweep类的成员函数MarkReachableObjects。

StickyMarkSweep

uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin());

uintptr_t end = reinterpret_cast<uintptr_t>(space->End());

atomic_finger_ = static_cast<int32_t>(0xFFFFFFFF);

uintptr_t

MarkSweep .RecursiveMark

Populates the mark stack based on the set of marked objects and

// recursively marks until the mark stack is emptied.

void MarkSweep::RecursiveMark() {

base::TimingLogger::ScopedSplit split("RecursiveMark", &timings_);

......

if (kUseRecursiveMark) {

const bool partial = GetGcType() == kGcTypePartial;

ScanObjectVisitor scan_visitor(this);

auto* self = Thread::Current();

ThreadPool* thread_pool = heap_->GetThreadPool();

size_t thread_count = GetThreadCount(false);

const bool parallel = kParallelRecursiveMark && thread_count > 1;

mark_stack_->Reset();

for (const auto& space : GetHeap()->GetContinuousSpaces()) {

if ((space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect) ||

(!partial && space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect)) {

current_mark_bitmap_ = space->GetMarkBitmap();

......

if (parallel) {

// We will use the mark stack the future.

// CHECK(mark_stack_->IsEmpty());

// This function does not handle heap end increasing, so we must use the space end.

uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin());

uintptr_t end = reinterpret_cast<uintptr_t>(space->End());

atomic_finger_ = static_cast<int32_t>(0xFFFFFFFF);

// Create a few worker tasks.

const size_t n = thread_count * 2;

while (begin != end) {

uintptr_t start = begin;

uintptr_t delta = (end - begin) / n;

delta = RoundUp(delta, KB);

if (delta < 16 * KB) delta = end - begin;

begin += delta;

auto* task = new RecursiveMarkTask(thread_pool, this, current_mark_bitmap_, start,

begin);

thread_pool->AddTask(self, task);

}

thread_pool->SetMaxActiveWorkers(thread_count - 1);

thread_pool->StartWorkers(self);

thread_pool->Wait(self, true, true);

thread_pool->StopWorkers(self);

} else {

// This function does not handle heap end increasing, so we must use the space end.

uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin());

uintptr_t end = reinterpret_cast<uintptr_t>(space->End());

current_mark_bitmap_->VisitMarkedRange(begin, end, scan_visitor);

}

}

}

}

ProcessMarkStack(false);

}

MarkStackPush () {

mark_stack_pos_ /= 2;

}

for (mirror::Object **it = mark_stack_->Begin(), **end = mark_stack_->End(); it < end; ) {

mirror::Object**it = mark_stack_->Begin **end = mark_stack_->End; it < end;

Mark Sweep Partial Mark Sweep

Sticky Mark Sweep Allocation Stack3

Image Zygote AllocationSpace

ReMarkRoots CardTable

. 调用成员函数ProcessReferences处理Soft Reference、Weak Reference、Phantom Reference和Finalizer Reference等引用对象。

Soft Weak Phantom Finalizer Reference、Phantom

Runtime

Marking阶段对Card

Handle Dirty Objects过程中处理的。

我们知道,Image Space、Zygote Space和Allocation Space都是Continuous Space,它们的回收策略分别为kGcRetentionPolicyNeverCollect、kGcRetentionPolicyAlwaysCollect和kGcRetentionPolicyFullCollect,

void MarkSweep::SweepCallback(size_t num_ptrs, Object** ptrs, void* arg) {

SweepCallbackContext* context = static_cast<SweepCallbackContext*>(arg);

MarkSweep* mark_sweep = context->mark_sweep;

Heap* heap = mark_sweep->GetHeap();

space::AllocSpace* space = context->space;

Thread* self = context->self;

Locks::heap_bitmap_lock_->AssertExclusiveHeld(self);

// Use a bulk free, that merges consecutive objects before freeing or free per object?

// Documentation suggests better free performance with merging, but this may be at the expensive

// of allocation.

size_t freed_objects = num_ptrs;

// AllocSpace::FreeList clears the value in ptrs, so perform after clearing the live bit

size_t freed_bytes = space->FreeList(self, num_ptrs, ptrs);

heap->RecordFree(freed_objects, freed_bytes);

mark_sweep->freed_objects_.fetch_add(freed_objects);

mark_sweep->freed_bytes_.fetch_add(freed_bytes);

}

Object** ptrs

参数ptrs指向一组需要回收的对象占用的内存块的地址,而参数num_ptrs则表示这组内存块的个数。第三个参数arg指向一个SweepCallbackContext对象,这个对象的成员变量space描述了参数ptrs指向的内存块是所属的Space。有了这些信息之后,就可以调用相应的Space的成员函数FreeList进行真正的垃圾回收了。我们知道,Allocation Space是使用DlMallocSpace来描述的,因此,这里就是调用DlMallocSpace类的成员函数FreeList来回收内存。

从前面ART运行时为新创建对象分配内存的过程分析一文可以知道,DlMallocSpace类是通过C库提供的内存管理接口malloc来分配内存的,因此,它在回收内存时,也是使用对应的C库内存管理接口free来回收内存。这一点与Dalvik虚拟机垃圾收集(GC)过程分析一文分析的Dalvik虚拟机的垃圾回收逻辑也是一样的。

MarkSweep类的静态成员函数SweepCallback最后还调用了Heap类的成员函数Record记录了当前释放的对象个数和内存字节数,以及更新Mark Sweep内部的释放对象个数和内存字节数。

MarkSweep类的静态成员函数ZygoteSweepCallback的实现如下所示:

MarkSweep

SweepCallbackContext*

AllocSpace*

freed_objects (对象数) freed_bytes_(字节数)

size_t freed_objects = 0;

size_t freed_bytes = 0;

for (const Object* obj : large_live_objects->GetObjects()) {

if (!large_mark_objects->Test(obj)) {

freed_bytes += large_object_space->Free(self, const_cast<Object*>(obj));

++freed_objects;

}

}

size_t freed_bytes = 0;

Large Object Space

从前面ART运行时为新创建对象分配内存的过程分析一文可以知道,ART运行时使用的Large Object Space是一个LargeObjectMapSpace,它通过映射匿名共享内存为新创建对象分配内存,因此,LargeObjectMapSpace类的成员函数Free来释放内存时,就相应地删除对应的匿名共享内存就行了,如下所示:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片

size_t LargeObjectMapSpace::Free(Thread* self, mirror::Object* ptr) {

MutexLock mu(self, lock_);

MemMaps::iterator found = mem_maps_.find(ptr);

CHECK(found != mem_maps_.end()) << "Attempted to free large object which was not live";

DCHECK_GE(num_bytes_allocated_, found->second->Size());

size_t allocation_size = found->second->Size();

num_bytes_allocated_ -= allocation_size;

--num_objects_allocated_;

delete found->second;

mem_maps_.erase(found);

return allocation_size;

}

iterator found mem-maps_ find

found second Size

FreeList(self, chunk_freed_objects, objects_to_chunk_free);

FreeList

1. ART运行时堆的划分和管理更细致,它分为Image Space、Zygote Space、Allocation Space和Large Object Space四个Space,再加上一个Allocation Stack。其中,Allocation Space和Large Object Space和Dalvik虚拟机的Zygote堆和Active堆作用是一样的,而其余的Space则有特别的作用,例如,Image Space的对象是永远不需要回收的。

2. ART运行时的每一个Space都有不同的回收策略,ART运行时根据这个特性提供了Mark Sweep、Partial Mark Sweep和Sticky Mark Sweep等三种回收力度不同的垃圾收集器。其中,Mark Sweep的垃圾回收力度最大,它会同时回收Zygote Space、Allocation Space和Large Object Space的垃圾,Partial Mark Sweep的垃圾回收力度居中,它只会同时回收Allocation Space和Large Object Space的垃圾,而Sticky Mark Sweep的垃圾回收力度最小,它只会回收Allocation Stack的垃圾,即上次GC以后分配出来的又不再使用了的对象。力度越大的垃圾收集器,回收垃圾时需要的时候也就越长。这样我们就可以在应用程序运行的过程中根据不同的情景使用不同的垃圾收集器,那就可以更有效地执行垃圾回收过程。

3. ART运行时充分地利用了设备的CPU多核特性,在并行GC的执行过程中,将每一个并发阶段的工作划分成多个子任务,然后提交给一个线程池执行,这样就可以更高效率地完成整个GC过程,避免长时间对应用程序造成停顿。

Image Zygote Allocation Large Space

Active堆、Card Zygote

0x01-0x03

0000 0001 0000 0010 0000 0011

CPU要对成员变量c进行访问时,只需要一个读周期即可

0x00处读取了4个字节(注意由于是32位架构),

0x00 这个字节存放c

然后将0x01-0x03的3个字节暂存

接着又花费了一个读周期读取了从0x04-0x07的4字节数据,将0x04这个字节与刚刚暂存的3个字节进行拼接从而读取到成员变量i的值。

0x04 -0x07共4个字节;接下来看数据成员s的自身对齐值

pragma pack (value) value

pragma pack (2)

pragma pack()

sizeof struct A sizeof struct B

假设变量a存放在内存中的起始地址为0x00,那么其成员变量c的起始地址为0x00,

自身对齐值 指定对齐值 有效对齐值:上述两个对齐值中最小的那个。

c =1 4 0x00%1==0 0x00

i = 4 4 0x01%4 != 0 因此它应该被存放在0x04地址处,占用0x05,0x06,0x07共4个字节

s= 2 4 0x08 % 2 == 0 0x08

A = 4 4 0x0A%4 != 0

由此可见sizeof(struct A)的结果应该是=1+3(空闲空间)+4+2+2(结构体补充)=12字节。

07.#pragma pack (2) /* 指定按2字节对齐 */

08.struct B {

09. char c;

10. short s;

11. int i;

12.};

c = 1 2 1 0x00%1==0 0x00

s= 2 2 2 0x01 % 2 != 0 0x02 0x03

i = 4 2 2 0x04 % 2 = 0 0x04 0x05 0x06 0x07

假设编译器按默认4字节进行对齐

view plaincopy to clipboardprint?

01.#pragma pack(8)

02.struct S1 {

03. char a;

04. long b;

05.};

06.

07.struct S2 {

08. char c;

09. struct S1 d;

10. long long e;

11.};

12.#pragma pack()

13.

pragma pack(8) 8 字节对齐

#pragma pack()

sizeof (struct S1)

自身对齐值 指定对齐值 有效对齐值:上述两个对齐值中最小的那个。

c =1 4 0x00%1==0 0x00

i = 4 4 0x01%4 != 0 因此它应该被存放在0x04地址处,占用0x05,0x06,0x07共4个字节

s= 2 4 0x08 % 2 == 0 0x08

A = 4 4 0x0A%4 != 0

sizeof S1

a =1 8 1 0x00%1==0 0x00

b = 4 84 0x01%4 != 0 因此它应该被存放在0x04地址处,占用0x05,0x06,0x07共4个字节

sizeof S2

c= 1 81 0x00%1==0 0x00

S1 = S1的自身对齐值为成员的最大自身对齐值,即4字节

8 4 0x01%4 != 0 0x04开始8个字节,并且占用8个字节(0x04+0x08=0x0C),其中0x01-0x03被用来填充。

e = 8 8 8 0x0d%8 != 0 0x10 开始8个字节

我们一般说的对齐在N上,都是指有效对齐在N上。

Heap和Stack

简单说下:

Heap内存是指java运行环境用来分配给对象和JRE类的内存. 是应用的内存空间.

Stack内存是相对于线程Thread而言的, 它保存线程中方法中短期存在的变量值和对Heap中对象的引用等.

Stack内存, 顾名思义, 是类Stack方式, 总是后进先出(LIFO)的.

我们通常说的GC的针对Heap内存的. 因为Stack内存相当于是随用随销的.

Heap和Stack

Class Load

System Class 系统Class Loader加载的类. 例如java运行环境中rt.jar中类, 比如java.util.* package中的类.

Thread 运行中的线程

JNI 中的本地/全局变量, 用户自定义的JNI代码或是JVM内部的.

Busy Monitor 任何调用了wait()或notify()方法, 或是同步化的(synchronized)的东西. 可以理解为同步监控器.

Java本地实例, 还在运行的Thread的stack中的方法创建的对象.

Class Loader

Thread

JNI

wait notifyAll synchronized Java Stack

Eden Survivor Unrefer

Refer

Young Old Performance

Generation

GC那些事儿--Android内存优化第一弹

/p/5db05db4f5ab

Android是如何管理App内存的--Android内存优化第二弹

/p/4ad716c72c12

dex2oat

onReceive BroadcastReceiver () {

}

startService

LRUCache

Heap内存是指java运行环境用来分配给对象和JRE类的内存 Size在系统限制的最大值之内是随着应用的使用情况而变化的

dalvik.vm.heapstartsize

getprop

Tools, 出来接活了--Android内存优化第三弹

/p/080473ae050b

Memory Monitor

Dump Java Heap HPROF Viewer了 Analyzer

Allocation Traking按钮

Allocation Tracker

HPROF Viewer

Class View

App Image Zygote framework Heap

Class List View

Package Tree View

GC Root

Instance Depth Dominating Size

Reference Tree

Allocation Tracker

Group Method

Group Allocator

Method视图中的列含义如下:

列 解释

Method 方法

Count 该方法分配的实例总数

Size 该方法分配的内存总量(byte)

MAT Java Heap Heap dumps文件

LeakCanary

$ adb shell dumpsys meminfo com.udinic.perfdemo

Memory MAT

Memory Monitor, HPROF Viewer, MAT等等

HPROF Viewer MAT

ListenerManager

private List<SampleListener> listeners = new ArrayList<>();

ListenerManager.getInstance().addListener(this);

Analyzer Tasks Reference Tree

此例中, 比较简单, 可以很清晰看到是ListenerManager的静态单例sInstance最终支配了MemoryLeakActivity. sIntance连接到GC Roots, 故而导致MemoryLeakActivity GC Roots可达, 无法被回收.

Package Tree View

Dominate Tree

对象没有被回收是因为他有到GC Roots的可达路径

GC Roots

LeakCanary install

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。