12.2 — The stack and the heap - Learn C++

文章推薦指數: 80 %
投票人數:10人

With stack allocated memory, the compiler can keep track of the relationship between a variable's name and it's memory address, and translate ... Thememorythataprogramusesistypicallydividedintoafewdifferentareas,calledsegments:Thecodesegment(alsocalledatextsegment),wherethecompiledprogramsitsinmemory.Thecodesegmentistypicallyread-only.Thebsssegment(alsocalledtheuninitializeddatasegment),wherezero-initializedglobalandstaticvariablesarestored.Thedatasegment(alsocalledtheinitializeddatasegment),whereinitializedglobalandstaticvariablesarestored.Theheap,wheredynamicallyallocatedvariablesareallocatedfrom.Thecallstack,wherefunctionparameters,localvariables,andotherfunction-relatedinformationarestored.Forthislesson,we’llfocusprimarilyontheheapandthestack,asthatiswheremostoftheinterestingstufftakesplace.TheheapsegmentTheheapsegment(alsoknownasthe“freestore”)keepstrackofmemoryusedfordynamicmemoryallocation.Wetalkedabouttheheapabitalreadyinlesson11.11--Dynamicmemoryallocationwithnewanddelete,sothiswillbearecap.InC++,whenyouusethenewoperatortoallocatememory,thismemoryisallocatedintheapplication’sheapsegment.int*ptr=newint;//ptrisassigned4bytesintheheap int*array=newint[10];//arrayisassigned40bytesintheheapTheaddressofthismemoryispassedbackbyoperatornew,andcanthenbestoredinapointer.Youdonothavetoworryaboutthemechanicsbehindtheprocessofhowfreememoryislocatedandallocatedtotheuser.However,itisworthknowingthatsequentialmemoryrequestsmaynotresultinsequentialmemoryaddressesbeingallocated!int*ptr1=newint; int*ptr2=newint; //ptr1andptr2maynothavesequentialaddressesWhenadynamicallyallocatedvariableisdeleted,thememoryis“returned”totheheapandcanthenbereassignedasfutureallocationrequestsarereceived.Rememberthatdeletingapointerdoesnotdeletethevariable,itjustreturnsthememoryattheassociatedaddressbacktotheoperatingsystem.Theheaphasadvantagesanddisadvantages:Allocatingmemoryontheheapiscomparativelyslow.Allocatedmemorystaysallocateduntilitisspecificallydeallocated(bewarememoryleaks)ortheapplicationends(atwhichpointtheOSshouldcleanitup).Dynamicallyallocatedmemorymustbeaccessedthroughapointer.Dereferencingapointerisslowerthanaccessingavariabledirectly.Becausetheheapisabigpoolofmemory,largearrays,structures,orclassescanbeallocatedhere.ThecallstackThecallstack(usuallyreferredtoas“thestack”)hasamuchmoreinterestingroletoplay.Thecallstackkeepstrackofalltheactivefunctions(thosethathavebeencalledbuthavenotyetterminated)fromthestartoftheprogramtothecurrentpointofexecution,andhandlesallocationofallfunctionparametersandlocalvariables.Thecallstackisimplementedasastackdatastructure.Sobeforewecantalkabouthowthecallstackworks,weneedtounderstandwhatastackdatastructureis.ThestackdatastructureAdatastructureisaprogrammingmechanismfororganizingdatasothatitcanbeusedefficiently.You’vealreadyseenseveraltypesofdatastructures,suchasarraysandstructs.Bothofthesedatastructuresprovidemechanismsforstoringdataandaccessingthatdatainanefficientway.Therearemanyadditionaldatastructuresthatarecommonlyusedinprogramming,quiteafewofwhichareimplementedinthestandardlibrary,andastackisoneofthose.Considerastackofplatesinacafeteria.Becauseeachplateisheavyandtheyarestacked,youcanreallyonlydooneofthreethings:LookatthesurfaceofthetopplateTakethetopplateoffthestack(exposingtheoneunderneath,ifitexists)Putanewplateontopofthestack(hidingtheoneunderneath,ifitexists)Incomputerprogramming,astackisacontainerdatastructurethatholdsmultiplevariables(muchlikeanarray).However,whereasanarrayletsyouaccessandmodifyelementsinanyorderyouwish(calledrandomaccess),astackismorelimited.Theoperationsthatcanbeperformedonastackcorrespondtothethreethingsmentionedabove:Lookatthetopitemonthestack(usuallydoneviaafunctioncalledtop(),butsometimescalledpeek())Takethetopitemoffofthestack(doneviaafunctioncalledpop())Putanewitemontopofthestack(doneviaafunctioncalledpush())Astackisalast-in,first-out(LIFO)structure.Thelastitempushedontothestackwillbethefirstitempoppedoff.Ifyouputanewplateontopofthestack,thefirstplateremovedfromthestackwillbetheplateyoujustpushedonlast.Laston,firstoff.Asitemsarepushedontoastack,thestackgrowslarger--asitemsarepoppedoff,thestackgrowssmaller.Forexample,here’sashortsequenceshowinghowpushingandpoppingonastackworks:Stack:empty Push1 Stack:1 Push2 Stack:12 Push3 Stack:123 Pop Stack:12 Pop Stack:1 Theplateanalogyisaprettygoodanalogyastohowthecallstackworks,butwecanmakeabetteranalogy.Considerabunchofmailboxes,allstackedontopofeachother.Eachmailboxcanonlyholdoneitem,andallmailboxesstartoutempty.Furthermore,eachmailboxisnailedtothemailboxbelowit,sothenumberofmailboxescannotbechanged.Ifwecan’tchangethenumberofmailboxes,howdowegetastack-likebehavior?First,weuseamarker(likeapost-itnote)tokeeptrackofwherethebottom-mostemptymailboxis.Inthebeginning,thiswillbethelowestmailbox(onthebottomofthestack).Whenwepushanitemontoourmailboxstack,weputitinthemailboxthatismarked(whichisthefirstemptymailbox),andmovethemarkeruponemailbox.Whenwepopanitemoffthestack,wemovethemarkerdownonemailbox(soit’spointedatthetopnon-emptymailbox)andremovetheitemfromthatmailbox.Anythingbelowthemarkerisconsidered“onthestack”.Anythingatthemarkerorabovethemarkerisnotonthestack.ThecallstacksegmentThecallstacksegmentholdsthememoryusedforthecallstack.Whentheapplicationstarts,themain()functionispushedonthecallstackbytheoperatingsystem.Thentheprogrambeginsexecuting.Whenafunctioncallisencountered,thefunctionispushedontothecallstack.Whenthecurrentfunctionends,thatfunctionispoppedoffthecallstack.Thus,bylookingatthefunctionspushedonthecallstack,wecanseeallofthefunctionsthatwerecalledtogettothecurrentpointofexecution.Ourmailboxanalogyaboveisfairlyanalogoustohowthecallstackworks.Thestackitselfisafixed-sizechunkofmemoryaddresses.Themailboxesarememoryaddresses,andthe“items”we’repushingandpoppingonthestackarecalledstackframes.Astackframekeepstrackofallofthedataassociatedwithonefunctioncall.We’lltalkmoreaboutstackframesinabit.The“marker”isaregister(asmallpieceofmemoryintheCPU)knownasthestackpointer(sometimesabbreviated“SP”).Thestackpointerkeepstrackofwherethetopofthecallstackcurrentlyis.Wecanmakeonefurtheroptimization:Whenwepopanitemoffthecallstack,weonlyhavetomovethestackpointerdown--wedon’thavetocleanuporzerothememoryusedbythepoppedstackframe(theequivalentofemptyingthemailbox).Thismemoryisnolongerconsideredtobe“onthestack”(thestackpointerwillbeatorbelowthisaddress),soitwon’tbeaccessed.Ifwelaterpushanewstackframetothissamememory,itwilloverwritetheoldvaluewenevercleanedup.ThecallstackinactionLet’sexamineinmoredetailhowthecallstackworks.Hereisthesequenceofstepsthattakesplacewhenafunctioniscalled:Theprogramencountersafunctioncall.Astackframeisconstructedandpushedonthestack.Thestackframeconsistsof:Theaddressoftheinstructionbeyondthefunctioncall(calledthereturnaddress).ThisishowtheCPUrememberswheretoreturntoafterthecalledfunctionexits.Allfunctionarguments.MemoryforanylocalvariablesSavedcopiesofanyregistersmodifiedbythefunctionthatneedtoberestoredwhenthefunctionreturnsTheCPUjumpstothefunction’sstartpoint.Theinstructionsinsideofthefunctionbeginexecuting.Whenthefunctionterminates,thefollowingstepshappen:RegistersarerestoredfromthecallstackThestackframeispoppedoffthestack.Thisfreesthememoryforalllocalvariablesandarguments.Thereturnvalueishandled.TheCPUresumesexecutionatthereturnaddress.Returnvaluescanbehandledinanumberofdifferentways,dependingonthecomputer’sarchitecture.Somearchitecturesincludethereturnvalueaspartofthestackframe.OthersuseCPUregisters.Typically,itisnotimportanttoknowallthedetailsabouthowthecallstackworks.However,understandingthatfunctionsareeffectivelypushedonthestackwhentheyarecalledandpoppedoffwhentheyreturngivesyouthefundamentalsneededtounderstandrecursion,aswellassomeotherconceptsthatareusefulwhendebugging.Atechnicalnote:onsomearchitectures,thecallstackgrowsawayfrommemoryaddress0.Onothers,itgrowstowardsmemoryaddress0.Asaconsequence,newlypushedstackframesmayhaveahigheroralowermemoryaddressthanthepreviousones.AquickanddirtycallstackexampleConsiderthefollowingsimpleapplication:intfoo(intx) { //b returnx; }//fooispoppedoffthecallstackhere intmain() { //a foo(5);//fooispushedonthecallstackhere //c return0; }Thecallstacklookslikethefollowingatthelabeledpoints:a:main() b:foo()(includingparameterx) main() c:main() StackoverflowThestackhasalimitedsize,andconsequentlycanonlyholdalimitedamountofinformation.OnWindows,thedefaultstacksizeis1MB.Onsomeunixmachines,itcanbeaslargeas8MB.Iftheprogramtriestoputtoomuchinformationonthestack,stackoverflowwillresult.Stackoverflowhappenswhenallthememoryinthestackhasbeenallocated--inthatcase,furtherallocationsbeginoverflowingintoothersectionsofmemory.Stackoverflowisgenerallytheresultofallocatingtoomanyvariablesonthestack,and/ormakingtoomanynestedfunctioncalls(wherefunctionAcallsfunctionBcallsfunctionCcallsfunctionDetc…)Onmodernoperatingsystems,overflowingthestackwillgenerallycauseyourOStoissueanaccessviolationandterminatetheprogram.Hereisanexampleprogramthatwilllikelycauseastackoverflow.Youcanrunitonyoursystemandwatchitcrash:#include intmain() { intstack[10000000]; std::cout< voidfoo() { foo(); std::cout<



請為這篇文章評分?