首页 畅享游戏,快乐生活!
手机版
扫描查看手机站

强制GC是怎么玩的10种?强制gc是怎么玩的10种模式

时间:2023-11-15 18:44:58 编辑:

老铁们,大家好,相信还有很多朋友对于强制GC是怎么玩的10种和强制gc是怎么玩的10种模式的相关问题不太懂,没关系,今天就由我来为大家分享分享强制GC是怎么玩的10种以及强制gc是怎么玩的10种模式的问题,文章篇幅可能偏长,希望可以帮助到大家,下面一起来看看吧!

一:背景

在玩C的时候,经常会用void*来指向一段内存地址开端,然后再将其强转成尺度更小的char*或int*来丈量一段内存,参考如下代码:

nintmain()n{ntvoid*ptr=malloc(sizeof(int)*10);nntint*int_ptr=(int*)ptr;ntchar*char_ptr=(char*)ptr;n}nn

由于C的自由度比较大,想怎么玩就怎么玩,带来的弊端就是容易隐藏着一些不易发现的bug,归根到底还是程序员的功底不扎实,C++设计者觉得不能把程序员想的太厉害,应该要力所能及的帮助程序员避掉一些不必要的潜在bug,并且还要尽最大努力的避免对性能有过多的伤害,所以就出现了4个强制类型转换运算符。

const_castreinterpret_castdynamic_caststatic_cast

既然C++做了归类,必然就有其各自用途,接下来我们逐一和大家聊一下。

二:理解四大运算符1.const_cast

这是四个运算符中最好理解的,玩过C++的都知道,默认情况下是不能修改一个const变量,比如下面这样:

nintmain()n{ntconstinti=10;nti=12;n}nn

这段代码肯定是要报错的,那如果我一定要实现这个功能,如何做呢?这就需要用到const_cast去掉它的常量符号,然后对i进行操作即可,所以修改代码如下:

nintmain()n{ntconstinti=10;ntautoj=const_cast<int*>(&i);nt*(j)=12;n}nn2.reinterpret_cast

从名字上看就是一个重新解释转换,很显然这个非常底层,如果大家玩过windbg,应该知道用dt命令可以将指定的内存地址按照某一个结构体丈量出来,比如说C#的CLR在触发GC时,会有gc_mechanisms结构,参考代码如下:

n0:000>dtWKS::gc_mechanisms0x7ffb6ba96e60ncoreclr!WKS::gc_mechanismsn+0x000gc_index:1n+0x008condemned_generation:0n0n+0x00cpromotion:0n0n+0x010compaction:0n1n+0x014loh_compaction:0n0n+0x018heap_expansion:0n0n+0x01cconcurrent:0n+0x020demotion:0n0n+0x024card_bundles:0n1n+0x028gen0_reduction_count:0n0n+0x02cshould_lock_elevation:0n0n+0x030elevation_locked_count:0n0n+0x034elevation_reduced:0n0n+0x038minimal_gc:0n0n+0x03creason:0(reason_alloc_soh)n+0x040pause_mode:1(pause_interactive)n+0x044found_finalizers:0n0n+0x048background_p:0n0n+0x04cb_state:0(bgc_not_in_process)n+0x050allocations_allowed:0n1n+0x054stress_induced:0n0n+0x058entry_memory_load:0n+0x05cexit_memory_load:0nn

其实reinterpret_cast大概也是干这个事的,参考代码如下:

ntypedefstruct_Point{ntintx;ntinty;n}Point;nnintmain()n{ntPointpoint={10,11};nnt//内存地址ntvoid*ptr=&point;nnt//根据内存地址丈量出PointntPoint*ptr_point=reinterpret_cast<Point*>(ptr);nntprintf("x=%d",ptr_point->x);n}nn

从代码看,我直接根据ptr地址丈量出了Point结构,说实话这个和C玩法就比较类似了。

3.dynamic_cast

在多态场景下,有时候会遇到这样的一个问题,一个父类有多个子类,我现在手拥一个父类,我不知道能不能将它转换为其中一个子类,要试探一下看看,那怎么去试探呢?类似C#中的as运算符,在C++中就需要用dynamic_cast来做这件事情,参考如下:

n//点nclassPoint{npublic:ntPoint(intx,inty):x(x),y(y){}ntvirtualvoidshow(){}npublic:ntintx;ntinty;n};nn//矩形nclassRectangle:publicPoint{npublic:ntRectangle(intx,inty,intw,inth):Point(x,y),w(w),h(h){}npublic:ntintw;ntinth;n};nn//三角形nclassTriangle:publicPoint{npublic:ntTriangle(intx,inty,intz):Point(x,y),z(z){}npublic:ntintz;n};nnintmain()n{ntPoint*p1=newRectangle(10,20,100,200);ntPoint*p2=newTriangle(4,5,6);nnt//将p1转成子类Triangle会报错的ntTriangle*t1=dynamic_cast<Triangle*>(p1);nntif(t1==nullptr){nttprintf("p1不能转成Triangle");nt}n}nn

对,场景就是这个,p1其实是Rectangle转上去的,这时候你肯定是不能将它向下转成Triangle,问题就在这里,很多时候你并不知道此时的p1是哪一个子类。

接下来的一个问题是,C++并不像C#有元数据,那它是如何鉴别呢?其实这用了RTTI技术,哪里能看出来呢?哈哈,看汇编啦。

ntTriangle*t1=dynamic_cast<Triangle*>(p1);n00831D57push0n00831D59pushoffsetTriangle`RTTITypeDescriptor'(083C150h)n00831D5EpushoffsetPoint`RTTITypeDescriptor'(083C138h)n00831D63push0n00831D65moveax,dwordptr[p1]n00831D68pusheaxn00831D69call___RTDynamicCast(083104Bh)n00831D6Eaddesp,14hn00831D71movdwordptr[t1],eaxnn

从汇编可以看到编译器这是带夹私货了,在底层偷偷的调用了一个___RTDynamicCast函数在运行时帮忙检测的,根据cdcel调用协定,参数是从右到左,恢复成代码大概是这样。

n___RTDynamicCast(&p1,0,&Point,&Triangle,0)nn3.static_cast

从名字上就能看出,这个强转具有static语义,也就是编译阶段就生成好了,具体安全不安全,它就不管了,就拿上面的例子,将dynamic_cast改成static_cast看看有什么微妙的变化。

nintmain()n{ntPoint*p1=newRectangle(10,20,100,200);ntPoint*p2=newTriangle(4,5,6);nntTriangle*t1=static_cast<Triangle*>(p1);nntprintf("x=%d,y=%d,z=%d",t1->x,t1->y,t1->z);n}nn

我们发现居然转成功了,而且Triangle的值也是莫名奇怪,直接取了Rectangle的前三个值,如果这是生产代码,肯定要挨批了。。。

接下来简单看下汇编代码:

ntTriangle*t1=static_cast<Triangle*>(p1);n00DF5B17moveax,dwordptr[p1]n00DF5B1Amovdwordptr[t1],eaxnntprintf("x=%d,y=%d,z=%d",t1->x,t1->y,t1->z);n00DF5B1Dmoveax,dwordptr[t1]n00DF5B20movecx,dwordptr[eax+0Ch]n00DF5B23pushecxn00DF5B24movedx,dwordptr[t1]n00DF5B27moveax,dwordptr[edx+8]n00DF5B2Apusheaxn00DF5B2Bmovecx,dwordptr[t1]n00DF5B2Emovedx,dwordptr[ecx+4]n00DF5B31pushedxn00DF5B32pushoffsetstring"x=%d,y=%d,z=%d"(0DF8C80h)n00DF5B37call_printf(0DF145Bh)n00DF5B3Caddesp,10hnn

从代码中看,它其实就是将p1的首地址给了t1,然后依次把copy偏移值+4,+8,+0C,除了转换这个,还可以做一些int,long,double之间的强转,当然也是一样,编译时汇编代码就已经生成好了。

好了,本篇就说这么多,希望对你有帮助。

END,本文到此结束,如果可以帮助到大家,还望关注本站哦!

热门文章

推荐专题

更多>>

游戏推荐

更多>>