2Alloc

graph LR
subgraph CollectorType
kCollectorTypeCC
kCollectorTypeMC
kCollectorTypeSS
kCollectorTypeGSS

kCollectorTypeMS
kCollectorTypeCMS
end

subgraph AllocatorType
kCollectorTypeMS-->MallocSpace
kCollectorTypeCMS-->MallocSpace

kCollectorTypeCC-->RegionSpace
kCollectorTypeMC-->BumpPointerSpace
kCollectorTypeSS-->BumpPointerSpace
kCollectorTypeGSS-->BumpPointerSpace


MallocSpace-->|kUseRosAlloc|kAllocatorTypeRosAlloc
MallocSpace-->kAllocatorTypeDlMalloc     
RegionSpace-->|use_tlab_|kAllocatorTypeRegionTLAB
RegionSpace-->kAllocatorTypeRegion
BumpPointerSpace-->|use_tlab_|kAllocatorTypeTLAB
BumpPointerSpace-->kAllocatorTypeBumpPointer

end

heap.cc

Heap::ChangeCollector(CollectorType)

void Heap::ChangeCollector(CollectorType collector_type) {
    /*CollectorType是一个枚举变量,用于定义不同的回收器类型。collector_type_是
      Heap类的成员变量,描述当前设定的回收器类型。对笔者所搭建的模拟器而言,虚拟机使用的
      回收器类型为kCollectorTypeCMS。CMS是ConcurrentMarkSweep的缩写。它是标记
      清除垃圾回收算法的一种。本书后续章节会详细介绍它们。此处,读者仅作简单了解即可。 */
    if (collector_type != collector_type_) {
        collector_type_ = collector_type;//设置垃圾回收器类型
        ......
        switch (collector_type_) {
            case kCollectorTypeCC: {//CC是Concurrent Copying的缩写
                .....
                if (use_tlab_) {//是否使用TLAB。本例中不使用它,所以use_tlab_为false
                    //ChangeAllocator函数将设置内存分配器的类型
                    ChangeAllocator(kAllocatorTypeRegionTLAB);
                } else {
                    ChangeAllocator(kAllocatorTypeRegion);
                }
                break;
            }
            case kCollectorTypeMC://MC:Mark Compact
            case kCollectorTypeSS://SS:Semi-space
            //GSS:改进版的SS
            case kCollectorTypeGSS:{
                .....
                if (use_tlab_) {
                    ChangeAllocator(kAllocatorTypeTLAB);
                } else {
                    ChangeAllocator(kAllocatorTypeBumpPointer);
                }
                break;
            }
        case kCollectorTypeMS: {//MS:mark-sweep
            ......
            ChangeAllocator(kUseRosAlloc ? kAllocatorTypeRosAlloc :
                            kAllocatorTypeDlMalloc);
        break;
        }
        case kCollectorTypeCMS: {//本例对应这种情况
            .....
            //kUseRosAlloc默认为true
            ChangeAllocator(kUseRosAlloc ? kAllocatorTypeRosAlloc : kAllocatorTypeDlMalloc);
                break;
            }
            .....
        }
        ......
    }
}

ChangeAllocator(AllocatorType)

void Heap::ChangeAllocator(AllocatorType allocator) {
    //current_allocator_为Heap成员变量,表示当前所设定的内存分配器类型
    if (current_allocator_ != allocator) {
        current_allocator_ = allocator;
        MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
        //下面这两个函数比较关键,我们来看它们
        SetQuickAllocEntryPointsAllocator(current_allocator_);
        Runtime::Current()->GetInstrumentation()->ResetQuickAllocEntryPoints();
    }
}

quick_alloc_entrypoints.cc::SetQuickAllocEntryPointsAllocator

/*SetQuickAllocEntryPointsAllocator函数定义在quick_alloc_entrypoints.cc文件中。
  请读者注意这个文件的文件名,它是quickallocentrypoints。ART虚拟机以机器码运行Java程序的
  时候,如果涉及内存分配有关的指令(下文将介绍new  instance/array机器码的处理),则需要跳
  转到和内存分配有关的入口地址去执行。这些内存分配的入口地址都定义在这个quick_alloc_entrypoints.cc
  文件中。
  entry_points_allocator是一个静态变量,默认取值为DlMalloc,表示默认使用dlmalloc作为内存
  分配器。而SetQuickAllocEntryPointsAllocator可以修改它的值。下文将见到这个静态变量的作用。 */
static gc::AllocatorType entry_points_allocator = gc::kAllocatorTypeDlMalloc;
//修改entry_poionts_allocator静态变量的取值
void SetQuickAllocEntryPointsAllocator(gc::AllocatorType allocator) {
    entry_points_allocator = allocator;
}

instrumentation.cc

Instrumentation::ResetQuickAllocEntryPoints

void Instrumentation::ResetQuickAllocEntryPoints() {
    Runtime* runtime = Runtime::Current();
    if (runtime->IsStarted()) {
        MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
        //针对每一个线程对象调用ResetQuickAllocEntryPointsForThread函数。其内部将
        //调用Thread的ResetQuickAllocEntryPointsForThread
        runtime->GetThreadList()->ForEach(ResetQuickAllocEntryPointsForThread,  nullptr);
    }
}

Thread::ResetQuickAllocEntryPointsForThread

thread.h

class Thread{
    ...
    /*每一个线程对象都包含tlsPtr_成员,而这个成员中有一个quick_entrypoints,它包含了很多入口
      地址,它们在Java指令经编译得到的机器码中大量被调用。其实,它们就是机器码(也就是由Java
      开发人员编写的程序逻辑)和虚拟机交互的入口。相关知识请读者回顾本书前面介绍的与虚拟机执行
      有关的内容。*/
    struct PACKED(sizeof(void*)) tls_ptr_sized_values {
        QuickEntryPoints quick_entrypoints;
    }tlsPtr_;
void Thread::ResetQuickAllocEntryPointsForThread() {
    //修改tlsPtr_ quick_entrypoins结构体
    ResetQuickAllocEntryPoints(&tlsPtr_.quick_entrypoints);
}

quick_alloc_entrypoints.cc::ResetQuickAllocEntryPoints

void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints) {
#if !defined(__APPLE__) || !defined(__LP64__)
    //这个变量我们在上文中介绍过了。以笔者所搭建的模拟器为例,它的取值是kAllocatorTypeRosAlloc
    switch (entry_points_allocator) {
        case gc::kAllocatorTypeDlMalloc: {
            SetQuickAllocEntryPoints_dlmalloc(qpoints, entry_points_instrumented);
            return;
        }
        case gc::kAllocatorTypeRosAlloc: {
            //entry_points_instrumented也是一个静态变量,表示是否使用辅助工具
            //(instrumentation的含义),默认为false。我们不讨论它
            SetQuickAllocEntryPoints_rosalloc(qpoints, entry_points_instrumented);
            return;
        }
        ......
    }
    .....
    UNREACHABLE();
}

quick_alloc_entrypoints.cc::SetQuickAllocEntryPoints##suffix

//在SetQuickAllocEntryPoints_rosalloc函数中,rosalloc是下面的suffix
//所以,下面代码中pAllocObject的取值就是art_quick_alloc_object_rosalloc
void SetQuickAllocEntryPoints##suffix(QuickEntryPoints* qpoints,\
               bool instrumented) { \
    if (instrumented) { ......\
    } else { \
        qpoints->pAllocObject = art_quick_alloc_object##suffix; \
        ......
    } \
}
//借助suffix,我们可以定义不同内存分配器所对应的artAllocObjectFromCodeXXX函数
extern "C" mirror::Object* artAllocObjectFromCode ##suffix##suffix2( \
        uint32_t type_idx, ArtMethod* method, Thread* self) { \
    ScopedQuickEntrypointChecks sqec(self); \
    .....\略过一些其他情况的处理,感兴趣的读者可自行阅读
    //AllocObjectFromCode我们在解释执行模式中见过了
    return AllocObjectFromCode<false, instrumented_bool>(type_idx, method,
                self, allocator_type); \
} \
  
extern "C" mirror::Array* artAllocArrayFromCode##suffix##suffix2( \
        uint32_t type_idx, int32_t component_count, ArtMethod* method, \
            Thread* self) { \
    ScopedQuickEntrypointChecks sqec(self); \
    //AllocArrayFromCode我们也在上文中介绍过了
    return AllocArrayFromCode<false, instrumented_bool>(type_idx,\
            component_count, method, self, allocator_type); \
} \

解释执行

interpreter_switch_impl.cc

ExecuteSwitchImpl

template<bool do_access_check, bool transaction_active>
JValue ExecuteSwitchImpl(.....) {
    ......
    case Instruction::NEW_INSTANCE: {
        Object* obj = nullptr;
        Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(),
            shadow_frame.GetMethod(),self, false, do_access_check);
        if (LIKELY(c != nullptr)) {
            if (UNLIKELY(c->IsStringClass())) {
                gc::AllocatorType allocator_type =
                    Runtime::Current()->GetHeap()->GetCurrentAllocator();
                //下面这个函数对象类的代码,请读者自行研究
                mirror::SetStringCountVisitor visitor(0);
                //如果new一个String对象,则调用String Alloc函数
                obj = String::Alloc<true>(self, 0, allocator_type, visitor);//main
            } else {
                //如果new非String对象,则调用AllocObjectFromCode函数
                obj = AllocObjectFromCode<do_access_check, true>(//main
                inst->VRegB_21c(), shadow_frame.GetMethod(), self,
                Runtime::Current()->GetHeap()->GetCurrentAllocator());
            }
        }
        ......
        break;
    }
    case Instruction::NEW_ARRAY: {
        int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
        //如果new一个数组,则调用AllocArrayFromCode函数
        Object* obj = AllocArrayFromCode<do_access_check, true>(//main
            inst->VRegC_22c(), length, shadow_frame.GetMethod(), self,
            Runtime::Current()->GetHeap()->GetCurrentAllocator());
        ......
        break;
        }
    .....
}

array.h

class MANAGED Array : public Object {
    ......
private:
        int32_t length_;//元素的个数
        /*用于存储数组元素的内容。注意,虽然first_element_元素长度是32位,但它其实只是一
          块存储空间。该数组元素的个数需要根据Java层中对应数组元素所占位长来计算。比如,假设
          Java层中要创建包含4个short元素的数组。那么,first_element_数组的长度就是2。
          因为uint32_t为32位,而Java层short类型的位长是16,。*/
        uint32_t first_element_[0];
};

string.h

String::Alloc

class MANAGED String FINAL : public Object {
    .....
    int32_t count_;
    uint32_t hash_code_;
    uint16_t value_[0]; //value_数组才是真正存储字符串内容的地方。
    .....
};
template <bool kIsInstrumented, typename PreFenceVisitor>
inline String* String::Alloc(Thread* self, int32_t utf16_length,
               gc::AllocatorType allocator_type,
               const PreFenceVisitor& pre_fence_visitor) {
    //注意参数,utf16_length代表以UTF-16编码的字符个数。也就是说,一个字符占2个字节
    //sizeof(String)将返回String类的大小(不包括value_数组的内容)
    constexpr size_t header_size = sizeof(String);
    size_t length = static_cast<size_t>(utf16_length);
    size_t data_size = sizeof(uint16_t) * length;//计算字符串内容所需的内存大小
    //计算最终所需分配的内存大小
    size_t size = header_size + data_size;
    //size按8字节向上对齐
    size_t alloc_size = RoundUp(size, kObjectAlignment);
    Class* string_class = GetJavaLangString();
    .....
    gc::Heap* heap = Runtime::Current()->GetHeap();
    //调用Heap AllocObjectWithAllocator函数分配内存,main
    return down_cast<String*>(
        heap->AllocObjectWithAllocator<kIsInstrumented, true>(self,
            string_class, alloc_size,allocator_type, pre_fence_visitor));
}

entrypoint_utils-inl.h

AllocObjectFromCode

inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
        ArtMethod* method, Thread* self, gc::AllocatorType allocator_type) {
    ......//我们仅考察内存分配的调用逻辑
    //klass代表所要创建的对象的类。调用它的Alloc函数
    return klass->Alloc<kInstrumented>(self, allocator_type);
}

Class::Alloc

//class-inl.h
template<bool kIsInstrumented, bool kCheckAddFinalizer>
inline Object* Class::Alloc(Thread* self,gc::AllocatorType allocator_type){
    .....//我们仅考察内存分配的调用逻辑
    mirror::Object* obj =
        heap->AllocObjectWithAllocator<kIsInstrumented, false>(self, this,
                        this->object_size_,allocator_type, VoidFunctor());
    ......
    return obj;
}

AllocArrayFromCode

template <bool kAccessCheck, bool kInstrumented>
inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
    int32_t component_count, ArtMethod* method, Thread* self,
        gc::AllocatorType allocator_type) {
    ......
    return mirror::Array::Alloc<kInstrumented>(self, klass, component_count,
                  klass->GetComponentSizeShift(), allocator_type);
}

Array::Alloc

array-inl.h
template <bool kIsInstrumented, bool kFillUsable>
inline Array* Array::Alloc(Thread* self, Class* array_class,
            int32_t component_count, size_t component_size_shift,
            gc::AllocatorType allocator_type) {
    /*下面的ComputeArraySize将根据要创建数组的元素个数(component_count决定)和元素的数据
      类型(由component_size_shift间接决定可参考primitive.hComponentSizeShift函数)
      来计算该数组对象最终所需要的内存大小。   */
    size_t size = ComputeArraySize(component_count, component_size_shift);
    ......
    gc::Heap* heap = Runtime::Current()->GetHeap();
    Array* result;
    if (!kFillUsable) {//kFillUsable默认为false
        SetLengthVisitor visitor(component_count);
        result = down_cast<Array*>(
            heap->AllocObjectWithAllocator<kIsInstrumented, true>(self,
                          array_class, size,allocator_type, visitor));
    } else { ......}
    ......
    return result;
}

heap(-inl).h

AllocObjectWithAllocator

/*AllocObjectWithAllocator为模板函数,包含三个模板参数:
    kInstrumented:和工具使用有关。我们不讨论它的情况
    kCheckLargeObject:判断要分配的内存大小是否属于大对象的范围
    PreFenceVisitor:一个函数对象,AllocObjectWithAllocator完成工作后会调用它。*/
template <bool kInstrumented, bool kCheckLargeObject, typename PreFenceVisitor>
    ALWAYS_INLINE mirror::Object* AllocObjectWithAllocator(Thread* self,
        mirror::Class* klass, size_t byte_count, AllocatorType allocator, const PreFenceVisitor& pre_fence_visitor) {
//AllocObjectWithAllocator函数参数的含义都很简单,笔者不拟赘述。另外,请读者注意
//解释执行和机器码模式下调用这个函数时传入的内存器分配类型都是kAllocatorTypeRosAlloc

    mirror::Object* obj;
    /*kCheckLargeObject为true并且ShouldAllocLargeObject返回true时,将转入
      AllocLargeObject函数。ShouldAllocLargeObject判断条件我们在上文介绍
      LargeObjectSpace时已经讲过,如果要分配的内存大于12KB(由Heap成员变量
      large_object_threshhold_控制,默认为12KB),并且所创建对象的类型为基础数据类
      型的数组或String,则属于大对象内存分配的范畴。*/
    if (kCheckLargeObject && UNLIKELY(ShouldAllocLargeObject(klass , byte_count))) {
        //AllocLargeObject函数将以kAllocatorTypeLOS为内存分配器的类型再次调用AllocObjectWithAllocator函数
        obj = AllocLargeObject<kInstrumented, PreFenceVisitor>(self, &klass, byte_count, pre_fence_visitor);
        /*如果obj不为空,表明内存分配成功,返回obj。如果obj为空指针,则清除可能产生的异常
          但还需要继续尝试分配内存。因为kAllocatorTypeLOS内存分配器没有内存可分配,但其他
          类型的内存分配器(本例是kAllocatorTypeRosAlloc)可能还有内存供分配)。   */
        if (obj != nullptr) {  return obj; }
        else { self->ClearException(); }
    }
    size_t bytes_allocated;
    size_t usable_size;
    size_t new_num_bytes_allocated = 0;

    if (allocator == kAllocatorTypeTLAB || allocator == kAllocatorTypeRegionTLAB) {
        //所需内存大小按8字节向上对齐
        byte_count = RoundUp(byte_count, space::BumpPointerSpace::kAlignment);
    }
    /*如果使用线程本地内存资源(TLAB),则先判断线程对象(self指定)TLAB是否还有足够
      内存。如果有,则直接从线程的TLAB中分配内存。注意,只有BumpPointerSpace和
      RegionSpace支持TLAB。rosalloc也有线程本地内存资源,只不过名字不叫TLAB。 */
    if ((allocator == kAllocatorTypeTLAB || allocator ==  kAllocatorTypeRegionTLAB) &&  byte_count <= self->TlabSize()) {
      	obj = self->AllocTlab(byte_count);
   	    obj->SetClass(klass);
        ......
        bytes_allocated = byte_count;
        usable_size = bytes_allocated;
        pre_fence_visitor(obj, usable_size);//调用回调对象
        QuasiAtomic::ThreadFenceForConstructor();
    } else if (!kInstrumented && allocator == kAllocatorTypeRosAlloc&&
            (obj = rosalloc_space_->AllocThreadLocal(self, byte_count , &bytes_allocated)) && LIKELY(obj != nullptr)) {
        //如果使用rosalloc,则调用RosAllocSpace的AllocThreadLocal在self所属线程
        //对应的内存空间中分配资源。上文已经对rosalloc做了详尽介绍,感兴趣的读者可自行研究这部分代码
        obj->SetClass(klass);
        .....//
        usable_size = bytes_allocated;
        pre_fence_visitor(obj, usable_size);
        QuasiAtomic::ThreadFenceForConstructor();
    } else {
        /*如果前面的if条件均不满足(并不一定说明内存分配失败,有可能是内存分配器不满足if
          的条件),则调用TryToAlloce函数进行内存分配。下文将单独介绍它。  */
        size_t bytes_tl_bulk_allocated = 0;
        obj = TryToAllocate<kInstrumented, false>(self, allocator, byte_count,
                    &bytes_allocated, &usable_size, &bytes_tl_bulk_allocated);
        if (UNLIKELY(obj == nullptr)) {
            //TryToAllocate如果返回空指针,说明内存资源有点紧张,下面将调用
            //AllocateInternalWithGc再次进行内存分配尝试,但该函数内部会开展垃圾回收。
            //下文将单独介绍AllocateInternalWithGc函数
            obj = AllocateInternalWithGc(self, allocator,.....);
            if (obj == nullptr) {
            //如果obj依然为空指针,还需要判断是否有异常发生。根据注释所言,如果上面代码执行
            //过程中切换了内存分配器的类型,则obj为空并且没有待投递的异常。
            if (!self->IsExceptionPending()) {
                /*调用AllocObject。注意,这里并没有传入内存分配器类型。如上面所说,此时
                  内存分配器类型已经发生了变化(否则不会满足if的条件)。AllocObject将使用
                  新的内存分配器类型重新调用一次AllocObjectWithAllocator。  */
                return AllocObject<true>(self,klass, byte_count,  pre_fence_visitor);
            }
            //返回空指针,说明确实没有内存。此时一定会有一个OutOfMemory的异常等待我们
            return nullptr;
        }
    }
    //如果代码执行到此处,说明内存分配成功
    obj->SetClass(klass);
    ......
    //下面这个if代码块也和垃圾回收有关。我们后续章节再讨论它们
    if (collector::SemiSpace::kUseRememberedSet&& UNLIKELY(
                    allocator == kAllocatorTypeNonMoving)) {
            ....
        WriteBarrierField(obj, mirror::Object::ClassOffset(), klass);
    }
    pre_fence_visitor(obj, usable_size);
    QuasiAtomic::ThreadFenceForConstructor();
    //Heap的num_bytes_allocated_成员变量保存了当前所分配的内存大小
    new_num_bytes_allocated = static_cast<size_t>(
        num_bytes_allocated_.FetchAndAddRelaxed(bytes_tl_bulk_allocated)) + bytes_tl_bulk_allocated;
    }
    .....
        /*下面的AllocatorHasAllocationStack函数将检查分配器的类型,如果分配器类型不为
          kAllocatorTypeBumpPointer、kAllocatorTypeTLAB、 kAllocatorTypeRegion、kAllocatorTypeRegionTLAB中时将返回true。
          PushOnAllocationStack的代码将把obj保存到self线程的对应数据结构中。详情见下文13.6.4.3节的介绍。*/
        if (AllocatorHasAllocationStack(allocator)) {
            PushOnAllocationStack(self, &obj);//main
    }
    //下面的if语句和GC有关,我们统一留待后续章节再介绍
    if (AllocatorMayHaveConcurrentGC(allocator) &&IsGcConcurrent()) {
        CheckConcurrentGC(self, new_num_bytes_allocated, &obj);
    }
    .......
    return obj;
}

Heap::TryToAllocate

template <const bool kInstrumented, const bool kGrow>
inline mirror::Object* Heap::TryToAllocate(Thread* self,
                                    AllocatorType allocator_type,.....) {
    /*TryToAllocate有一个模板参数kGrow。它的含义和Heap对内存水位线的控制有关。
      后续章节我们再来介绍与之有关的内容。注意,上文AllocObjectWithAllocator调用TryToAllocate时,kGrow设置为false   */
    ......
    mirror::Object* ret;
    //根据内存分配器的类型选择不同的内存分配器
    switch (allocator_type) {
        case kAllocatorTypeBumpPointer: {//使用BumpPointerSpace
            alloc_size = RoundUp(alloc_size, space::BumpPointerSpace::kAlignment);
            ret = bump_pointer_space_->AllocNonvirtual(alloc_size);
            .....
            break;
        }
        case kAllocatorTypeRosAlloc: {//使用RosAllocSpace
        if (kInstrumented && UNLIKELY(is_running_on_memory_tool_)) {
            ......
        } else {
            /*结合上文对rosalloc分配器的介绍可知,rosalloc分配内存时会先确定一个Run,然后
              从这个Run中找到空闲的slot作为最终的内存资源。如果这个Run没有空闲资源,则会先创建
              这个Run(其所包含的slot都需要分配好)。虽然我们此次要分配的内存只有alloc_size
              大小,但它可能会导致一个Run的内存被分配。所以,下面的MaxBytesBulkAllocated-
              ForNonvirtual函数返回能匹配alloc_size的slot所属的Run需要多大内存(一个Run
              包含多个slot。一个slot大于或等于alloc_size)。
              IsOutOfMemoryOnAllocation为Heap的成员函数,它将判断可能需要分配的内存
              大小是否超过水位线。如果超过水位线,则内存分配失败。*/
            size_t max_bytes_tl_bulk_allocated =
                rosalloc_space_->MaxBytesBulkAllocatedForNonvirtual(alloc_size);
            if (UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(allocator_type,
                                            max_bytes_tl_bulk_allocated))) {
                return nullptr;
            }
            //调用RosAllocSpace AllocNonVirtual分配内存
            ret = rosalloc_space_->AllocNonvirtual(self, alloc_size,...);
            }
            break;
        }
        case kAllocatorTypeDlMalloc: {//dlmalloc的处理
            ......
            break;
        }
        case kAllocatorTypeNonMoving: {
            /*non_moving_space_的类型为MallocSpace*。这说明kAllocatorTypeNonMoving
              并不是一种独立的内存分配算法,它只是MallocSpace的一种使用场景。从内存分配角度来
              说,下面的Alloc要么由RosAllocSpace实现,要么由DlMallocSpace实现。
              kAllocatorTypeNonMoving的真正作用和下一章要介绍的GC有关,我们后续碰到时再介绍 它们。 */
            ret = non_moving_space_->Alloc(self, alloc_size, bytes_allocated,
                                usable_size, bytes_tl_bulk_allocated);
            break;
        }
        case kAllocatorTypeLOS:....//其他内存分配器类型的处理,笔者不拟赘述
        case kAllocatorTypeTLAB:....
        case kAllocatorTypeRegion:....
        case kAllocatorTypeRegionTLAB:...
        ......
    }
    return ret;
}

Heap::AllocateInternalWithGc

原理图
graph LR
WaitForGcToComplete-->TryToAllocate1-->|failed|CollectGarbageInternal-->TryToAllocate2("TryToAllocate2")
-->|failed|CollectGarbageInternal2("GcTypeIteratorCollectGarbageInternal")-->TryToAllocateN("TryToAllocateN")
-->|failed|ThrowOutOfMemoryError
mirror::Object* Heap::AllocateInternalWithGc(Thread* self,
    AllocatorType allocator, bool instrumented,....,mirror::Class** klass) {
    ....
    /*WaitForGcToComplete:等待GC完成(如果当前正有GC任务的话)。返回值的类型GcType
      我们在7.6.2节中曾介绍过它。此处回顾如下:
      GcType为枚举变量,它有四种取值,对应垃圾回收力度由轻到重:
      (1) kGcTypeNone:没有做GC。
      (2) kGcTypeSticky:表示仅扫描和回收上次GC到本次GC这个时间段内所创建的对象
      (3) kGcTypePartial:仅扫描和回收应用进程自己的堆,不处理zygote的堆。这种方式和
          Android中Java应用程序的创建方式有关。在Android中,应用进程是zygote进程fork
          出来的。
      (4) kGcTypeFull:它将扫描APP自己以及它从父进程zygote继承得到的堆。
          垃圾回收时会由轻到重开展回收,以本例所设置的垃圾回收器类型kCollectorTypeCMS而言,
          它会由轻到重,分别尝试kGcTypeSticky、kGcTypePartial、kGcTypeFull。
          请读者注意,笔者在第14章中将介绍这几种回收策略的代码实现逻辑。*/
    collector::GcType last_gc = WaitForGcToComplete(kGcCauseForAlloc, self);
    .....
    //last_gc不为kGcTypeNone,表示系统完成了一次GC,再次尝试分配内存。注意,这次GC
    //并不是由AllocateInternalWithGc发起的
    if (last_gc != collector::kGcTypeNone) {
        mirror::Object* ptr = TryToAllocate<true, false>(self,....);
        if (ptr != nullptr) { return ptr; }
    }
    /*next_gc_type_表示我们要发起的GC粒度。它的取值和垃圾回收器类型有关。next_gc_type_
      的类型也是GcType。我们上文介绍过它的取值情况。   */
    collector::GcType tried_type = next_gc_type_;
    //CollectGarbageInternal将发起GC,注意它的最后一个参数表示是否回收
    //Soft Reference对象(详情见GC相关的知识)
    const bool gc_ran =
        CollectGarbageInternal(tried_type, kGcCauseForAlloc, false)  != collector::kGcTypeNone;
    ......
    if (gc_ran) {//gc_ran为true,表示执行了一次GC。现在,再次尝试分配内存
        mirror::Object* ptr = TryToAllocate<true, false>(self, ......);
        if (ptr != nullptr) { return ptr; }
    }
    //还是没有内存,此时,我们需要根据gc_plan_(数组),以上面代码中注释提到的CMS而言,
    //该数组的内容分别是kGcTypeSticky、kGcTypePartial、kGcTypeFull。下面的for循环将
    //由轻到重开展垃圾回收
    for (collector::GcType gc_type : gc_plan_) {
        if (gc_type == tried_type) { continue; }
        const bool plan_gc_ran = CollectGarbageInternal(gc_type, kGcCauseForAlloc, false) != collector::kGcTypeNone;
        ......
        if (plan_gc_ran) {//每执行一次回收就尝试分配一次内存
            mirror::Object* ptr = TryToAllocate<true, false>(self,.....);
            if (ptr != nullptr) { return ptr; }
        }
    }
    //再次尝试分配内存,但需要设置TryToAllocate的kGrow模板参数为true。读者可以看看
    //TryToAllocate函数的代码,对rosalloc而言,kGrow为true并没有多大用处
    mirror::Object* ptr = TryToAllocate<true, true>(self, allocator,....);
    if (ptr != nullptr) { return ptr; }

    //还是没有空余内存的话,则以最强力度(gc_plan_数组的末尾元素代表最强力度的GcType),
    //并且不放过soft reference对象(第三个参数为true)再做一次GC
    CollectGarbageInternal(gc_plan_.back(), kGcCauseForAlloc, true);
    .....
    ptr = TryToAllocate<true, true>(self, allocator,.....);
    if (ptr == nullptr) {
        //根据内存分配器的类型尝试做内存压缩(Compact)等操作。操作成功的话还会尝试
        //内存分配。这部分内容也和GC有关,我们后续章节再介绍
        ....
    }
    if (ptr == nullptr) {//设置OOM异常
        ThrowOutOfMemoryError(self, alloc_size, allocator);
    }
    return ptr;
}

Heap::PushOnAllocationStack

inline void Heap::PushOnAllocationStack(Thread* self, mirror::Object** obj) {
    //编译常量kUseThreadLocalAllocationStack表示是否使用线程的Allocation Stack,
    //默认取值为true。
    if (kUseThreadLocalAllocationStack) {
        /*调用Thread PushOnThreadLocalAllocationStack函数保存这个obj对象。该obj
          保存在线程的Allocation Stack中。注意,该函数如果返回false,说明Allocation
          Stack内存不足。此时需要调用Heap
      PushOnThreadLocalAllocationStackWithInternalGC函数为线程分配Allocation Stack的空间。  */
    if (UNLIKELY(!self->PushOnThreadLocalAllocationStack(*obj))) {
            PushOnThreadLocalAllocationStackWithInternalGC(self, obj);
        }
    } else if ......
}
inline bool Thread::PushOnThreadLocalAllocationStack(mirror::Object* obj) {
    if (tlsPtr_.thread_local_alloc_stack_top< tlsPtr_.thread_local_alloc_stack_end) {
        //obj存储到stack_top所指向的位置,此后递增stack_top的值
        tlsPtr_.thread_local_alloc_stack_top->Assign(obj);
        ++tlsPtr_.thread_local_alloc_stack_top;
        return true;
    }
    return false; //返回false,说明Allocation Stack空间不够
}

void Heap::PushOnThreadLocalAllocationStackWithInternalGC(Thread* self,
                mirror::Object** obj) {
    StackReference<mirror::Object>* start_address;
    StackReference<mirror::Object>* end_address;
    /*kThreadLocalAllocationStackSize取值为128,即每个线程有能存128个Object对象
      指针的空间。AtomicBumpBack的功能见上文对AtomicStack的讲解。  */
    while (!allocation_stack_->AtomicBumpBack(kThreadLocalAllocationStackSize, &start_address, &end_address)) {
        .......
        CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc,false);
    }
    //设置self线程的Allocation Stack
    self->SetThreadLocalAllocationStack(start_address, end_address);
}

thread.h

struct PACKED(sizeof(void*)) tls_ptr_sized_values {
    ......
    /*下面这两个成员变量的初始值为nullptr,它们标示了一段内存的起始和结束位置。代码中称
      这段内存为Allocation Stack。Allocation Stack就是一个栈容器,它存储的是一组
      StackReference<Object>元素。读者可以将一个StackReference<Object>实例看成一
      个指向Object的指针。 */
    StackReference<mirror::Object>* thread_local_alloc_stack_top;
    StackReference<mirror::Object>* thread_local_alloc_stack_end;
    ......

机器码执行

code_generator_x86.cc

image-20210213171954962

InstructionCodeGeneratorX86::VisitNewInstance

void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
    if (instruction->IsStringAlloc()) {//如果是创建String类型的对象
        Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
        MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize);
        /*根据thread.cc InitStringEntryPoints函数的设置可知,QuickEntryPoints
          pNewEmptyString指向java lang StringFactory newEmptyString函数的机器码
          入口地址。也就是说,如果创建String类型的对象,则会调用StringFactory类的
          newEmptyString函数。 */
        __ fs()->movl(temp,  Address::Absolute(QUICK_ENTRY_POINT(pNewEmptyString)));
        __ call(Address(temp, code_offset.Int32Value()));
        ......
        } else {
        /*参考instruction_builder.ccBuildNewInstance函数可知,下面的GetEntryPoint返回
          kQuickAllocObject或kQuickAllocObjectInitialized,它们分别对应QuickEntryPoints
          结构体里的pQuickAllocObject和pQuickAllocObjectInitialized成员变量。*/
        codegen_->InvokeRuntime(instruction->GetEntrypoint(),....);
        ......
    }
}

String::Alloc

//StringFactory.java
public static String newEmptyString() {
    //newStringFromChars最终将调用下面代码所示的native函数
    return newStringFromChars(EmptyArray.CHAR, 0, 0);
}
//最终会调用下面这个native函数
static native String newStringFromChars(int offset, int charCount,
            char[] data);
//java_lang_StringFactory.cc
static jstring StringFactory_newStringFromChars(JNIEnv* env, jclass,
               jint offset,jint char_count, jcharArray java_data) {
    .....
    gc::AllocatorType allocator_type =
                Runtime::Current()->GetHeap()->GetCurrentAllocator();
    //内部调用String Alloc函数。其内容我们在解释执行模式一节中已经介绍过了
    mirror::String* result = mirror::String::AllocFromCharArray<true>(
                        soa.Self(), char_count,char_array, offset,
                        allocator_type);
  return soa.AddLocalReference<jstring>(result);
}

InstructionCodeGeneratorX86::VisitNewArray

void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
    InvokeRuntimeCallingConvention calling_convention;
    __ movl(calling_convention.GetRegisterAt(0),
            Immediate(instruction->GetTypeIndex()));
    /*参考instruction_builder.ccProcessDexInstruction函数对NEW_ARRAY的处理,
      GetEntryPoint返回值为kQuickAllocArrayWithAccessCheck或kQuickAllocArray,
      它们分别对应QuickEntryPoints结构体里的pQuickAllocArrayWithAccessCheck和
      pQuickAllocArray成员变量。   */
    codegen_->InvokeRuntime(instruction->GetEntrypoint(),
                        instruction, instruction->GetDexPc(), nullptr);
    ......
}

Heap构造函数中所创建的Space

image-20210213192252388

图13-9 Heap构造函数中所创建的Space (heapSize=384MB)

Heap::Heap

Heap::Heap(size_t initial_size, size_t growth_limit,...
        size_t capacity,size_t non_moving_space_capacity,
        const std::string& image_file_name,.....
        CollectorType foreground_collector_type,
        CollectorType background_collector_type,
        space::LargeObjectSpaceType large_object_space_type,
        size_t large_object_threshold,....){
      ......
        /*foreground_collector_type:当应用程序处于前台(即用户能感知的情况)时GC的类型。
                此处为kCollectorTypeCMS(以后简称CMS)
        background_collector_type:当应用程序位于后台时GC的类型。此处为
                kCollectorTypeHomogeneousSpaceCompact(以后简称HSC)。注意,这是
                一种空间压缩的方法,可减少内存碎片。但需要较长时间暂停程序的运行,所以只能
                在程序位于后台(用户不可见)的时候来执行。

large_object_threshold:被认定为大对象的标准。来自runtime_options.def的
                LargeObjectThreshold参数,默认取值为Heap.h
                kDefaultLargeObjectThreshold(大小为3个内存页,此处为12KB)。*/

    //desired_collector_type_取值同foreground_collector_type,本例为kCollectorTypeCMS
    ChangeCollector(desired_collector_type_);
    //初始化live_bitmap_和mark_bitmap_成员变量,类型为HeapBitmap,读者可参考
    //7.6.1.1节
    live_bitmap_.reset(new accounting::HeapBitmap(this));
    mark_bitmap_.reset(new accounting::HeapBitmap(this));
......

Heap::AddSpace

void Heap::AddSpace(space::Space* space) {
    WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
    if (space->IsContinuousSpace()) {
        //根据图13-1,除了LargeObjectSpace外,其他的Space都属于ContinuousSpace
        space::ContinuousSpace* continuous_space = space->AsContinuousSpace();
        /*ContinuousSpace GetLiveBitmap和GetMarkBitmap是虚函数。其实现者为
          ContinuousMemMapAllocSpace。而ContinuousMemMapAllocSpace定义了
          live_bitmap_和mark_bitmap_两个成员变量。根据13.7.3节可知,只有DlMallocSpace
          和RosAllocSpace初始化了这两个成员变量。  */
        accounting::ContinuousSpaceBitmap* live_bitmap = continuous_space->GetLiveBitmap();
        accounting::ContinuousSpaceBitmap* mark_bitmap = continuous_space->GetMarkBitmap();
        if (live_bitmap != nullptr) {
   /*下面的live_bitmap_和mark_bitmap_为Heap的成员变量,类型为HeapBitmap。
              其详细信息可参考7.6.1.1节的内容。简单来说,下面的AddContinuousSpaceBitmap
              函数将把一个位图对象加到HeapBitmap continuous_space_bitmaps_
              (ContinuousSpaceBitmap数组)中去。*/
            live_bitmap_->AddContinuousSpaceBitmap(live_bitmap);
            mark_bitmap_->AddContinuousSpaceBitmap(mark_bitmap);
        }
        //continuous_spaces_为Heap的成员变量,类型为vector<ContinuousSpace*>,即
        //一个存储ContinuousSpace对象的数组。下面将continuous_space加到这个数组中
        continuous_spaces_.push_back(continuous_space);
        //对continuous_spaces_数组中的元素进行排序,内存空间起始位置小的排在前面。
        //图13-9中Space对象就是按这个顺序排列的(从左到右,内存起始地址由低到高)
        std::sort(continuous_spaces_.begin(), continuous_spaces_.end(),
                    [](const space::ContinuousSpace* a,
                       const space::ContinuousSpace* b) {
                return a->Begin() < b->Begin();
            });
        } else {
        //处理DiscontinuousSpace,也就是唯一的LargeObjectMapSpace
        space::DiscontinuousSpace* discontinuous_space = space->AsDiscontinuousSpace();
        //AddLargeObjectBitmap用于将位图对象加入HeapBitmap large_object_bitmaps_数组中
        live_bitmap_->AddLargeObjectBitmap(discontinuous_space->GetLiveBitmap());
        mark_bitmap_->AddLargeObjectBitmap(discontinuous_space->GetMarkBitmap());
        //discontinuous_spaces_为Heap成员变量,类型为vector<DiscontinuousSpace*>
        discontinuous_spaces_.push_back(discontinuous_space);
    }
    //如果Space可分配内存,则还需要将这个AllocSpace对象加到
    //Heap alloc_spaces_数组中保存,其类型为vector<AllocSpace*>
    if (space->IsAllocSpace()) {
        alloc_spaces_.push_back(space->AsAllocSpace());
    }
}

Heap::RemoveSpace

void Heap::RemoveSpace(space::Space* space) {
    WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
    if (space->IsContinuousSpace()) {
        space::ContinuousSpace* continuous_space = space->AsContinuousSpace();
        accounting::ContinuousSpaceBitmap* live_bitmap =continuous_space->GetLiveBitmap();
        accounting::ContinuousSpaceBitmap* mark_bitmap = continuous_space->GetMarkBitmap();
        if (live_bitmap != nullptr) {
            live_bitmap_->RemoveContinuousSpaceBitmap(live_bitmap);
            mark_bitmap_->RemoveContinuousSpaceBitmap(mark_bitmap);
        }
        auto it = std::find(continuous_spaces_.begin(), continuous_spaces_.end(), continuous_space);
        continuous_spaces_.erase(it);
    } else {
        ....//类似处理,操作discontinuous_spaces_数组
    }
    if (space->IsAllocSpace()) {
        auto it = std::find(alloc_spaces_.begin(), alloc_spaces_.end(),space->AsAllocSpace());
        alloc_spaces_.erase(it);
    }
}

CardTable,Space,RememberedSet,ModUionTable的关系

image-20210213192720762

image-20210213202259073

图13-10 分代GC示意

heap.cc

Heap::Heap

//构造方法
......
static constexpr size_t kMinHeapAddress = 4 * KB;
//CardTable的覆盖范围从4KB开始,到4GB结束。读者可参考图13-11
card_table_.reset(accounting::CardTable::Create(//main
            reinterpret_cast<uint8_t*>(kMinHeapAddress), 4 * GB - kMinHeapAddress));
......
if (collector::SemiSpace::kUseRememberedSet &&
                    non_moving_space_ != main_space_) {
    accounting::RememberedSet* non_moving_space_rem_set =
        new accounting::RememberedSet("Non-moving space remembered set",
                this, non_moving_space_);
    /*Heap中有一个名为remembered_sets_的成员变量,其数据类型为
    AllocationTrackingSafeMap<space::Space*,accounting::RememberedSet*,...>。
    读者可将AllocationTrackingSafeMap看作std map。下面的AddRememberedSet函数
    将把一个RememberedSet对象和它所关联的space_加入到remembered_sets_容器中。
    AddRememberedSet非常简单,请读者自行阅读。*/
    AddRememberedSet(non_moving_space_rem_set);
}

card_table(-inl).h/cc

CardTable::Create

CardTable* CardTable::Create(const uint8_t* heap_begin,
                      size_t heap_capacity) {
    /*CardTable类定义了几个编译常量,如下所示:
    static constexpr size_t kCardShift = 7;
    static constexpr size_t kCardSize = 1 <<kCardShift;//kCardSize值为128
    static constexpr uint8_t kCardClean = 0x0;
    static constexpr uint8_t kCardDirty = 0x70;*/
    //计算需要多少个Card
    size_t capacity = heap_capacity / kCardSize;
    std::string error_msg;
    //创建一个MemMap映射对象,其大小为capacity+256。
    std::unique_ptr<MemMap> mem_map(
        MemMap::MapAnonymous("card table", nullptr, capacity + 256,
                        PROT_READ | PROT_WRITE,...));
    //下面省略了一段代码,用于计算图13-11中提到的对齐区域,见下文介绍
    ......
    //创建CardTable对象。biased_begin是第一个card的位置,offset是用于计算偏移量的值
    return new CardTable(mem_map.release(), biased_begin, offset);
}

thread.cc

void Thread::InitCardTable() {
    //Heap GetCardTable返回Heap card_table_成员变量。这说明所有线程对象共用一个
    //CardTable。CardTable GetBiasedBegin函数返回这个CardTable用于存储记录的内存
    //空间的起始地址。
    tlsPtr_.card_table =
        Runtime::Current()->GetHeap()->GetCardTable()->GetBiasedBegin();
}
CardTable::CardTable(MemMap* mem_map, uint8_t* biased_begin, size_t offset)
    : mem_map_(mem_map), biased_begin_(biased_begin), offset_(offset) {
}

remembered_set.cc

RememberedSet

class RememberedSet {//为方便讲解,代码行位置有所调整
    public:
        //CardSet是类型别名,它是一个std set容器,key的类型为uint8_t*。一个元素代表
        //CardTable中的一个Card,也就是该Card的地址保存在CardSet中
        typedef std::set<uint8_t*, std::less<uint8_t*>,....>CardSet;
    private:
        //RememberedSet只有如下四个成员变量
        const std::string name_;//RememberedSet的名称
        Heap* const heap_;
        space::ContinuousSpace* const space_;//关联一个Space,读者可回顾图13-11
        CardSet dirty_cards_;
    public:
        /*RemeberedSet的构造函数。代码中有几处地方会创建RememberedSet对象
        (1) Heap构造函数中为non_moving_space_对象创建一个RememberedSet对象
        (2) CreateMallocSpaceFromMemMap函数,为每一个通过该函数创建的MallocSpace对象创建一个RememberedSet对象。
        注意,non_moving_space_虽然是MallocSpace对象,但它是由DlMallocSpace
        CreateFromMemMap函数创建而来,所以并不受上面第2条的影响。*/
        explicit RememberedSet(const std::string& name, Heap* heap,
                        space::ContinuousSpace* space)
            : name_(name), heap_(heap), space_(space) {}
        ....
        //RememberedSet成员函数较少,下面两个是其中最重要的成员函数,详情见下文代码分析
        void ClearCards();
        void UpdateAndMarkReferences(space::ContinuousSpace* target_space,
                        collector::GarbageCollector* collector);
        ......
};
ClearCards
void RememberedSet::ClearCards() {
    CardTable* card_table = GetHeap()->GetCardTable();
    RememberedSetCardVisitor card_visitor(&dirty_cards_);
        /*上文介绍了CardTable ModifyCardsAtomic函数的作用。此处的ClearCards函数将用到
          它。其功能为扫描space_对应的card,调用AgeCardVisitor函数获取card的新值,然后
          调用card_visitor函数对象。  */
    card_table->ModifyCardsAtomic(space_->Begin(), space_->End(),
                            AgeCardVisitor(), card_visitor);
}

/*ModifyCardsAtomic用于修改从scan_begin到scan_end内存范围对应CardTable
  card的值。修改前调用模板参数visitor函数对象,visitor需要返回该Card的新值。
  如果新值和旧值不同,则调用模板参数modified函数对象以通知外界。函数名中的Atomic意
  为原子操作。该函数的代码不短,但难度不大。*/
template <typename Visitor, typename ModifiedVisitor>
void ModifyCardsAtomic(uint8_t* scan_begin, uint8_t* scan_end,
            const Visitor& visitor,
            const ModifiedVisitor& modified);

class AgeCardVisitor {
    public:
        uint8_t operator()(uint8_t card) const {
            //参数card就是指CardTable中的一个Card。如果它的值为kCardDirty,则返回
            //0x6E(kCardDirty - 1),否则返回0。总之,card的新值不会是kCardDirty
        return (card == accounting::CardTable::kCardDirty) ? card - 1 : 0;
    }
};

class RememberedSetCardVisitor {
    public:
        explicit RememberedSetCardVisitor(
                 RememberedSet::CardSet* const dirty_cards)
            : dirty_cards_(dirty_cards) {}
    //expected_value为card的旧值(调用AgeCardVisitor之前的值),而
    //new_value为AgeCardVisitor返回的新值。此处没有用到new_value
    void operator()(uint8_t* card, uint8_t expected_value,
                    uint8_t new_value ATTRIBUTE_UNUSED) const {
        //如果card的值为kCardDirty,将其加入RememberedSet dirty_cards_ set容器中
        if (expected_value == CardTable::kCardDirty) {
          dirty_cards_->insert(card);
        }
    }
    private:
    RememberedSet::CardSet* const dirty_cards_;
};
UpdateAndMarkReferences
//遍历space_里所有存在跨Space引用的Object,然后对它们进行标记
void RememberedSet::UpdateAndMarkReferences(
                space::ContinuousSpace* target_space,
                collector::GarbageCollector* collector) {
    /*注意target_space的含义:UpdateAndMarkReferences将检查space_中的Object是否
      引用了位于target_space空间中的Object。*/
    CardTable* card_table = heap_->GetCardTable();

    //如果space_中的对象引用了target_space中的对象,则下面这个变量会被设置为true,
    //此时它的值为false
    bool contains_reference_to_target_space = false;
    //创建RememberedSetObjectVisitor函数对象
    RememberedSetObjectVisitor obj_visitor(target_space,&contains_reference_to_target_space,  collector);
    //要遍历一个ContinuousSpaceBitmap中所包含的Object,需要借助与之关联的位图对象
    ContinuousSpaceBitmap* bitmap = space_->GetLiveBitmap();
    CardSet remove_card_set;

    //dirty_cards容器已经包含了space_中那些标志为kDirtyCard的card信息。
    //下面的循环将遍历dirty_cards中的card
    for (uint8_t* const card_addr : dirty_cards_) {
        contains_reference_to_target_space = false;
        //将card地址转换为Space中对应的那个128字节单元的基地址。读者可回顾图13-11
        uintptr_t start = reinterpret_cast<uintptr_t>( card_table->AddrFromCard(card_addr));
        /*访问这个128字节单元中的Object,调用obj_visitor函数对象。7.6.1.1.3节SpaceBitmap的
          Walk函数。VisitMarkedRange与之类似,它将访问[start,start+128)这部分位图所对应内
          存空间中的Object们,每得到一个Object,就调用一次obj_visitor函数对象。VisitMarkRange
          函数中有一段参考性的实现代码,读者不妨一看(笔者在13.2节中曾展示过这段代码)。 */
        bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, obj_visitor);
        //如果这个128字节单元中的Object没有引用target_space中的Object,则对应的
        //card区域需要从dirty_cards容器中移除。先将这个card存到临时容器
        //remove_card_set中,后续将一次性移除它们
        if (!contains_reference_to_target_space) {
         remove_card_set.insert(card_addr);
        }
    }
    //从dirty_cards_中移除那些不存在跨Space引用的card
    for (uint8_t* const card_addr : remove_card_set) {
        dirty_cards_.erase(card_addr);
    }
}
class RememberedSetObjectVisitor {
    public:
        ......
        //SpaceBitmap VisitMarkedRange每找到一个Object都会调用下面这个函数
        void operator()(mirror::Object* obj) const {
        /*调用Object VisitReferences函数,传入另外一个函数对象。Object
          VisitReferences用于访问一个Object的引用型成员变量。想必读者已经猜到了,GC中
          常说的标记(Mark)操作肯定会用到这个函数来寻找对象之间的引用关系。13.8.3节将详细
          介绍此函数。 */
        RememberedSetReferenceVisitor visitor(target_space_,
                    contains_reference_to_target_space_,collector_);
        obj->VisitReferences(visitor, visitor);
        }
        ......
};
class RememberedSetReferenceVisitor {
    public:
    ......
    /*RememberedSetReferenceVisitor有多个调用函数以及回调函数。它们和Object
      VisitReferences的实现有关。本节仅看下面一个函数,其他几个函数的作用大同小异。 */
      void operator()(mirror::Object* obj, MemberOffset offset, bool is_static
    ATTRIBUTE_UNUSED) const {
    //offset是成员变量位于obj所在内存中的位置。将其转换成对应的Object。即ref_ptr
    //就是这个引用型成员变量所指向的那个Object
    mirror::HeapReference<mirror::Object>* ref_ptr = obj->GetFieldObjectReferenceAddr(offset);
    //判断target_space_中是否包含ref_ptr。如果包含,则存在跨Space的引用关系
    if (target_space_->HasAddress(ref_ptr->AsMirrorPtr())) {
            *contains_reference_to_target_space_ = true;
            //我们后续章节再介绍MarkHeapReference函数
            collector_->MarkHeapReference(ref_ptr);
        }
    }
    //其他几个回调函数,和Object VisitReferences有关
    ......
};

Object-inl.h

template <VerifyObjectFlags kVerifyFlags>
inline HeapReference<Object>* Object::GetFieldObjectReferenceAddr(MemberOffset field_offset) {
  if (kVerifyFlags & kVerifyThis) {
    VerifyObject(this);
  }
  return reinterpret_cast<HeapReference<Object>*>(reinterpret_cast<uint8_t*>(this) +
      field_offset.Int32Value());
}

MarkCard

发生下述依赖时,将a对应的card设置为kCardDirty

graph TB
a("a.b")-->|引用|b

解释执行模式下,iput-object指令将触发DoFieldPut函数被调用

interpreter_common.cc

DoFieldPut

bool DoFieldPut(Thread* self,... uint16_t inst_data){
    ......
    //f是代表目标成员变量的ArtField对象
    ArtField* f =
        FindFieldFromCode<find_type, do_access_check>(field_idx, ....
                            Primitive::ComponentSize(field_type));
    ......
    switch (field_type) {
    case Primitive::kPrimNot: {
        Object* reg = shadow_frame.GetVRegReference(vregA);
        ......
        f->SetObj<transaction_active>(obj, reg);
        break;
    }
    .....
}
  
//art_field-inl.h
template<bool kTransactionActive>
inline void ArtField::SetObj(mirror::Object* object,
                mirror::Object* new_value) {

    if (UNLIKELY(IsVolatile())) {.....}
    else {
        //调用Object SetFieldObject函数
        object->SetFieldObject<kTransactionActive>(GetOffset(), new_value);
    }
}
  
//object-inl.h
inline void Object::SetFieldObject(MemberOffset field_offset,  Object* new_value) {
    /*设置对应成员变量的值其不使用Write Barrier。其内部就是更新本Object对象
        field_offset内存处的值为new_value。不熟悉Object对象内存布局的读者请阅读8.7.4.2
        节的内容。 */
    SetFieldObjectWithoutWriteBarrier<...>(field_offset, new_value);
    //只要新值不为空,都需要调用Heap WriteBarrierField函数
    if (new_value != nullptr) {
        Runtime::Current()->GetHeap()->WriteBarrierField(this, field_offset, new_value);
        ......
    }
}
  
//heap.h
ALWAYS_INLINE void WriteBarrierField(const mirror::Object* dst,
            MemberOffset offset ATTRIBUTE_UNUSED,
            const mirror::Object* new_value ATTRIBUTE_UNUSED) {
    /*注意,WriteBarrierField只用到第一个参数dst,它就是成员变量被赋值的那个对象,而成员变
      量的新值(new_value表示)并未使用。在下面的代码中,上文Heap构造函数中已经见过card_table_
      了。而MarkCard将标记dst对应的Card标志为kCardDirty。其详情见下文的介绍。  */
    card_table_->MarkCard(dst);
}

MarkCard

ALWAYS_INLINE void MarkCard(const void *addr) {
    /*CardFromAddr返回addr对应的Card,然后设置其值为kCardDirty。从这里也可以看出,
      ART虚拟机中,一个Card为一个字节(CardFromAddr返回值类型为uint8_t*)。*/
     *CardFromAddr(addr) = kCardDirty;
}

inline uint8_t* CardTable::CardFromAddr(const void *addr) const {
    //由基地址加上addr右移7位(相当于除以128)以得到对应card的位置。而CardTable的基
    //准位置从biased_begin_算起
    uint8_t *card_addr = biased_begin_ +
                  (reinterpret_cast<uintptr_t>(addr) >>kCardShift);
    return card_addr;
}

bool IsDirty(const mirror::Object* obj) const {
    return GetCard(obj) == kCardDirty;
}
uint8_t GetCard(const mirror::Object* obj) const {
    return *CardFromAddr(obj);
}

Object-inl.h::VisitReferences

image-20210213203852276

template <bool kVisitNativeRoots = true,
          VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
          ReadBarrierOption kReadBarrierOption = kWithReadBarrier,
          typename Visitor,
          typename JavaLangRefVisitor = VoidFunctor>
    void VisitReferences(const Visitor& visitor, const JavaLangRefVisitor& ref_visitor) { 
    //klass为Object所属的类(即mirrorObject的成员变量klass)
    mirror::Class* klass = GetClass<kVerifyFlags, kReadBarrierOption>();
    //klass是Object第一个引用型成员变量,调用visitor来访问它
    visitor(this, ClassOffset(), false);
    //获取类的类型
    const uint32_t class_flags = klass->GetClassFlags<kVerifyNone>();
    if (LIKELY(class_flags == kClassFlagNormal)) {
        /*调用VisitInstanceFieldsReferences函数访问其引用型成员变量。这个函数的实现与
          我们在8.7.4.3节介绍的引用型成员变量在Object内存中的布局密切相关。我们在该节中还
          展示了下面这个函数内部将要调用的VisitFieldsReferences的代码。另外,VisitInstances-
          FieldsReferences用于访问对象的非静态引用型成员变量。*/
        VisitInstanceFieldsReferences<.....>(klass,  visitor);
    } else {//其他类标志位的处理。
        if ((class_flags &kClassFlagNoReferenceFields) == 0) {
            if (class_flags == kClassFlagClass) {
            //如果目标对象本身就是一个Java Class对象,则将其转换为Class对象,然后调用
            //mirror Class VisitReferences函数
            mirror::Class* as_klass = AsClass<...>();
            as_klass->VisitReferences<....>(klass, visitor);
            } else if (class_flags == kClassFlagObjectArray) {
                //如果是一个Object数组,则转换成mirror ObjectArray,调用它的
                //VisitReferences函数
                AsObjectArray<mirror::Object,.....>()->VisitReferences(visitor);
            } else if ((class_flags &kClassFlagReference) != 0) {
            //如果类的类型为Java Reference的一种,则先调用VisitInstanceFieldsReferences
            VisitInstanceFieldsReferences<...>(klass, visitor);
            //然后调用JavaLangRefVisitor。注意,第二个参数将目标对象转换成一个mirror
            //Reference对象
                ref_visitor(klass, AsReference<kVerifyFlags, kReadBarrierOption>());
            } else if (class_flags == kClassFlagDexCache) {
                //将自己转换为DexCache
                mirror::DexCache* const dex_cache = AsDexCache<....>();
                //调用DexCache VisitReference函数
                dex_cache->VisitReferences<...>(klass, visitor);
            } else {
                mirror::ClassLoader* const class_loader = AsClassLoader<...>();
                //将自己转换成ClassLoader,然后调用它的VisitReferences
                class_loader->VisitReferences<...>(klass, visitor);
            }
        }
    }
}

Visitor和JavaLangRefVisitor示例

class VisitorAndJavaLangRefVisitor {//同时支持Visitor和JavaLangRefVisitor
    /*Visitior需要重载如下所示的函数调用操作符。obj代表目标对象,offset代表目标对象中的
      某个引用型成员变量在内存中的位置(读者可回顾8.7.4.2节的内容以了解Object的内存布
      局),is_static表示该成员变量是否为static类型
    void operator()(mirror::Object* obj, MemberOffset offset,bool is_static) const{}

    /*JavaLangRefVisitor需要重载如下所示的函数调用操作符。klass代表目标对象所属的类,ref
      则是目标对象本身。注意,只有类的数据类型属于Java Reference的其中一种时(说明目标对象
      为mirror Reference对象),下面这个函数才会被调用。注意,它并不是用来访问成员变量,而是
      访问目标对象本身(将其从mirror Object转换成mirror Reference后)*/
    void operator()(mirror::Class* klass, mirror::Reference* ref) const{}

    //下面这两个函数是Visitor必须实现的成员函数,其使用场景见下文的介绍
    void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root)
        const {}
    void VisitRoot(mirror::CompressedReference<mirror::Object>* root)
        const { }
    ......
};

class-inl.h

Class::VisitReferences

template <bool kVisitNativeRoots,...,typename Visitor>
inline void Class::VisitReferences(mirror::Class* klass,
            const Visitor& visitor) {
    //调用mirror Object的VisitInstanceFieldsReferences函数以访问非静态的引用型成员变量
    VisitInstanceFieldsReferences<...>(klass, visitor);
    if (IsResolved<kVerifyFlags>()) {
        //访问静态引用型成员变量
        VisitStaticFieldsReferences<....>(this, visitor);
    }
    if (kVisitNativeRoots) {
        //类的成员函数(对应为ArtMethod)、成员变量(对应为ArtField)均定义在mirror
        //Class中。下面的VisitNativeRoots用于访问它们,来看代码
        VisitNativeRoots(visitor,
            Runtime::Current()->GetClassLinker()->GetImagePointerSize());
    }
}
template<class Visitor>
void Class::VisitNativeRoots(Visitor& visitor, size_t pointer_size) {
    //访问静态成员变量
    for (ArtField& field : GetSFieldsUnchecked()) {
        field.VisitRoots(visitor);
    }
    //访问非静态成员变量
    for (ArtField& field : GetIFieldsUnchecked()) {
        field.VisitRoots(visitor);
    }
    //GetMethods返回一个Class所定义的所有成员方法(不包括其继承得来的方法)。读者可回顾
    //8.7.4.1节的内容
    for (ArtMethod& method : GetMethods(pointer_size)) {
        method.VisitRoots(visitor, pointer_size);
    }
}

art_field-inl.h

ArtField::VisitRoots

template<typename RootVisitorType>
inline void ArtField::VisitRoots(RootVisitorType& visitor) {
    //调用函数对象的VisitRoot函数。declaring_class_是该成员变量所属的类
    visitor.VisitRoot(declaring_class_.AddressWithoutBarrier());
}

object_array-inl.h

ObjectArray::VisitReferences

template<class T> template<typename Visitor>
inline void ObjectArray<T>::VisitReferences(const Visitor& visitor) {
 const size_t length = static_cast<size_t>(GetLength());
    for (size_t i = 0; i < length; ++i) {
        visitor(this, OffsetOfElement(i), false);
    }
}

dex_cache-inl.h

DexCache::VisitReferences

template <bool kVisitNativeRoots,..., typename Visitor>
inline void DexCache::VisitReferences(mirror::Class* klass,
           const Visitor& visitor) {
    VisitInstanceFieldsReferences<...>(klass, visitor);
    if (kVisitNativeRoots) {
        //访问DexCache里的字符串信息。读者可回顾8.7.1.2节的内容
        //GetString返回DexCache strings_成员变量
        GcRoot<mirror::String>* strings = GetStrings();
        for (size_t i = 0, num_strings = NumStrings(); i != num_strings; ++i) {
        //调用Visitor VisitRootIfNonNull函数
        visitor.VisitRootIfNonNull(strings[i].AddressWithoutBarrier());
        }
        //访问DexCache里的类型信息(DexCache resolved_types_成员变量)
        GcRoot<mirror::Class>* resolved_types = GetResolvedTypes();
        for (size_t i = 0, num_types = NumResolvedTypes(); i != num_types; ++i) {
        visitor.VisitRootIfNonNull(resolved_types[i].AddressWithoutBarrier());
        }
    }//if判断结束
}

class_loader-inl.h

ClassLoader::VisitReferences

template <bool kVisitClasses,... typename Visitor>
inline void ClassLoader::VisitReferences(mirror::Class* klass,
                const Visitor& visitor) {
    VisitInstanceFieldsReferences<...>(klass, visitor);
    if (kVisitClasses) {
        ClassTable* const class_table = GetClassTable();
        if (class_table != nullptr) {
            //调用ClassTable的VisitRoots函数,内部将调用visitor的VisitRoots函数
            //请读者自行阅读ClassTable VisitRoots函数的实现,非常简单
            class_table->VisitRoots(visitor);
        }
    }
}