HTML5技术

CoreCLR源码探索(二) new是什么 - q303248153(4)

字号+ 作者:H5之家 来源:H5之家 2017-01-12 09:04 我要评论( )

这种new会在栈(stack)分配内存,所以不需要调用任何分配内存的函数 在一开始的例子中,myStruct在编译时就已经定义为一个本地变量,对本地变量的需要的内存会在函数刚进入的时候一并分配 这里我们先来看本地变量所

这种new会在栈(stack)分配内存,所以不需要调用任何分配内存的函数
在一开始的例子中,myStruct在编译时就已经定义为一个本地变量,对本地变量的需要的内存会在函数刚进入的时候一并分配
这里我们先来看本地变量所需要的内存是怎么计算的

先看Compiler::lvaAssignVirtualFrameOffsetsToLocals
源代码:

Compiler::lvaAssignVirtualFrameOffsetsToLocals() { // 省略部分代码...... for (cur = 0; alloc_order[cur]; cur++) { // 省略部分代码...... for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++) { // 省略部分代码...... // Reserve the stack space for this variable stkOffs = lvaAllocLocalAndSetVirtualOffset(lclNum, lvaLclSize(lclNum), stkOffs); } } }

再看Compiler::lvaAllocLocalAndSetVirtualOffset
源代码:

int Compiler::lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, int stkOffs) { // 省略部分代码...... /* Reserve space on the stack by bumping the frame size */ lvaIncrementFrameSize(size); stkOffs -= size; lvaTable[lclNum].lvStkOffs = stkOffs; // 省略部分代码...... return stkOffs; }

再看Compiler::lvaIncrementFrameSize
我们可以看到最终会加到compLclFrameSize这个变量中,这个变量就是当前函数总共需要在栈(Stack)分配的内存大小
源代码:

inline void Compiler::lvaIncrementFrameSize(unsigned size) { if (size > MAX_FrameSize || compLclFrameSize + size > MAX_FrameSize) { BADCODE("Frame size overflow"); } compLclFrameSize += size; }

现在来看生成机器码的代码,在栈分配内存的代码会在CodeGen::genFnProlog生成
源代码:

void CodeGen::genFnProlog() { // 省略部分代码...... // ARM64和其他平台的调用时机不一样,但是参数一样 genAllocLclFrame(compiler->compLclFrameSize, initReg, &initRegZeroed, intRegState.rsCalleeRegArgMaskLiveIn); }

再看CodeGen::genAllocLclFrame,这里就是分配栈内存的代码了,简单的rsp(esp)减去了frameSize
源代码:

CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn) { // 省略部分代码...... // sub esp, frameSize 6 inst_RV_IV(INS_sub, REG_SPBASE, frameSize, EA_PTRSIZE); }

总结:
JIT对struct的new会生成统一在栈分配内存的代码,所以你在IL中看不到new struct的指令
调用构造函数的代码会从后面的call指令生成

第一种new(对class的new)做了什么

从上面的分析我们可以知道第一种new先调用JIT_New分配内存,然后调用构造函数
在上面JIT_New的源代码中可以看到,JIT_New内部调用了AllocateObject

先看AllocateObject函数
源代码:

// AllocateObject will throw OutOfMemoryException so don't need to check // for NULL return value from it. OBJECTREF AllocateObject(MethodTable *pMT #ifdef FEATURE_COMINTEROP , bool fHandleCom #endif ) { // 省略部分代码...... Object *orObject = NULL; (pMT->HasCriticalFinalizer()) PrepareCriticalFinalizerObject(pMT); // 省略部分代码...... DWORD baseSize = pMT->GetBaseSize(); // 调用gc的帮助函数分配内存,如果需要向8对齐则调用AllocAlign8,否则调用Alloc if (pMT->RequiresAlign8()) { // 省略部分代码...... orObject = (Object *) AllocAlign8(baseSize, pMT->HasFinalizer(), pMT->ContainsPointers(), pMT->IsValueType()); } else { orObject = (Object *) Alloc(baseSize, pMT->HasFinalizer(), pMT->ContainsPointers()); } // 检查同步块索引(SyncBlock)是否为0 // verify zero'd memory (at least for sync block) _ASSERTE( orObject->HasEmptySyncBlockInfo() ); // 设置类型信息(MethodTable) if ((baseSize >= LARGE_OBJECT_SIZE)) { orObject->SetMethodTableForLargeObject(pMT); GCHeap::GetGCHeap()->PublishObject((BYTE*)orObject); } else { orObject->SetMethodTable(pMT); } // 省略部分代码...... return UNCHECKED_OBJECTREF_TO_OBJECTREF(oref); }

再看Alloc函数
源代码:

Object* Alloc(size_t size, BOOL bFinalize, BOOL bContainsPointers ) { INTERIOR_STACK_PROBE_FOR(GetThread(), static_cast<unsigned>(DEFAULT_ENTRY_PROBE_AMOUNT * 1.5)); if (GCHeapUtilities::UseAllocationContexts()) retVal = GCHeapUtilities::GetGCHeap()->Alloc(GetThreadAllocContext(), size, flags); else retVal = GCHeapUtilities::GetGCHeap()->Alloc(size, flags); if (!retVal) { ThrowOutOfMemory(); } END_INTERIOR_STACK_PROBE; return retVal; }

总结:
第一种new做的事情主要有

  • 调用JIT_New
  • 调用构造函数
  • 第二种new(对array的new)做了什么

    第二种new只调用了JIT_NewArr1,从上面JIT_NewArr1的源代码可以看到
    如果元素的类型是基元类型(int, double等)则会调用FastAllocatePrimitiveArray,否则会调用AllocateArrayEx

    先看FastAllocatePrimitiveArray函数
    源代码:

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • CoreCLR源码探索(一) Object是什么 - q303248153

      CoreCLR源码探索(一) Object是什么 - q303248153

      2017-01-06 11:04

    • 升讯威ADO.NET增强组件(源码):送给喜欢原生ADO.NET的你 - sheng.chao

      升讯威ADO.NET增强组件(源码):送给喜欢原生ADO.NET的你 - sheng.c

      2016-12-20 11:01

    • html5 Sortable.js 拖拽排序源码分析 - qq281113270

      html5 Sortable.js 拖拽排序源码分析 - qq281113270

      2016-11-04 15:00

    • MVC系列——MVC源码学习:打造自己的MVC框架(三:自定义路由规则) - 懒得安分

      MVC系列——MVC源码学习:打造自己的MVC框架(三:自定义路由规则)

      2016-11-03 18:00

    网友点评
    /