生活工程体验信仰哲学精神
投稿投诉
精神世界
探索历史
哲学文学
艺术价值
信仰创造
境界审美
体验技术
技能工具
工程信息
医学生产
生活运用
操作能力

内存映射小块内存申请brk和申请大块内存的Mmap分析

3月15日 逆落雪投稿
  一。前言
  本文为内存部分最后一篇,介绍内存映射。内存映射不仅是物理内存和虚拟内存间的映射,也包括将文件中的内容映射到虚拟内存空间。这个时候,访问内存空间就能够访问到文件里面的数据。而仅有物理内存和虚拟内存的映射,是一种特殊情况。本文首先分析用户态在堆中申请小块内存的brk和申请大块内存的mmap,之后会分析内核态的内存映射机制vmalloc,kmapatomic,swapperpgdir以及内核态缺页异常。二。用户态内存映射
  用户态调用malloc()会分配堆内存空间,而实际上则是完成了一次用户态的内存映射,根据分配空间的大小,内存映射对应的系统调用主要有brk()和mmap()(当然我们也可以直接调用mmap()来映射文件)。对小块内存(小于128K),C标准库使用brk()来分配,也就是通过移动堆顶的位置来分配内存。这些内存释放后并不会立刻归还系统,而是被缓存起来,这样就可以重复使用。而大块内存(大于128K),则直接使用内存映射mmap()来分配,也就是在文件映射段找一块空闲内存分配出去。这两种方式,自然各有优缺点。
  brk()方式的缓存,可以减少缺页异常的发生,提高内存访问效率。不过,由于这些内存没有归还系统,在内存工作繁忙时,频繁的内存分配和释放会造成内存碎片。
  mmap()方式分配的内存,会在释放时直接归还系统,所以每次mmap()都会发生缺页异常。在内存工作繁忙时,频繁的内存分配会导致大量的缺页异常,使内核的管理负担增大。这也是malloc()只对大块内存使用mmap()的原因。2。1小块内存申请
  brk()系统调用为sysbrk()函数,其参数brk是新的堆顶位置,而mmbrk是原堆顶位置。该函数主要逻辑如下将原来的堆顶和现在的堆顶按照页对齐地址比较大小,判断是否在同一页中如果同一页则不需要分配新页,直接跳转至setbrk,设置mmbrk为新的brk即可如果不在同一页如果新堆顶小于旧堆顶,则说明不是新分配内存而是释放内存,由此调用domunmap()释放如果是新分配内存,则调用findvma(),查找vmareastruct红黑树中原堆顶所在vmareastruct的下一个结构体,如果在二者之间有足够的空间分配一个页则调用dobrkflags()分配堆空间。如果不可以则分配失败。SYSCALLDEFINE1(brk,unsignedlong,brk){unsignedlongnewbrk,oldbrk,。。。。。。newbrkPAGEALIGN(brk);oldbrkPAGEALIGN(mmbrk);if(oldbrknewbrk){}Alwaysallowshrinkingbrk。domunmap()maydowngrademmapsemtoread。if(brkmmbrk){mmbrkmusttobeprotectedbywritemmapsemsoupdateitbeforedowngradingmmapsem。Whendomunmap()fails,mmbrkwillberestoredfromorigbrk。retdomunmap(mm,newbrk,oldbrknewbrk,uf,true);if(ret0){}elseif(ret1){}}Checkagainstexistingmmapmappings。nextfindvma(mm,oldbrk);if(nextnewbrkPAGESIZEvmstartgap(next))Ok,looksgoodletitrip。if(dobrkflags(oldbrk,newbrkoldbrk,0,uf)0)success:populatenewbrkoldbrk(mmdefflagsVMLOCKED)!0;if(downgraded)upread(mmmmapsem);elseupwrite(mmmmapsem);userfaultfdunmapcomplete(mm,uf);if(populate)mmpopulate(oldbrk,newbrkoldbrk);out:upwrite(mmmmapsem);}
  在dobrkflags()中,调用findvmalinks()找到将来的vmareastruct节点在红黑树的位置,找到它的父节点、前序节点。接下来调用vmamerge(),看这个新节点是否能够和现有树中的节点合并。如果地址是连着的,能够合并,则不用创建新的vmareastruct了,直接跳到out,更新统计值即可;如果不能合并,则创建新的vmareastruct,添加到anonvmachain链表中,也加到红黑树中。thisisreallyasimplifieddommap。itonlyhandlesanonymousmaps。eventuallywemaybeabletodosomebrkspecificaccountinghere。staticintdobrkflags(unsignedlongaddr,unsignedlonglen,unsignedlongflags,structlistheaduf){structvmareastructvma,structrbnoderblink,。。。。。。Clearoldmaps。thisalsodoessomeerrorcheckingforuswhile(findvmalinks(mm,addr,addrlen,prev,rblink,rbparent)){if(domunmap(mm,addr,len,uf))returnENOMEM;}。。。。。。Canwejustexpandanoldprivateanonymousmapping?vmavmamerge(mm,prev,addr,addrlen,flags,NULL,NULL,pgoff,NULL,NULLVMUFFDCTX);if(vma)createavmastructforananonymousmappingvmavmareaalloc(mm);if(!vma){vmunacctmemory(lenPAGESHIFT);returnENOMEM;}vmasetanonymous(vma);vmavmpageprotvmgetpageprot(flags);vmalink(mm,vma,prev,rblink,rbparent);out:perfeventmmap(vma);mmtotalvmlenPAGESHIFT;mmdatavmlenPAGESHIFT;if(flagsVMLOCKED)mmlockedvm(lenPAGESHIFT);vmavmflagsVMSOFTDIRTY;return0;}2。2大内存块申请
  大块内存的申请通过mmap系统调用实现,mmap既可以实现虚拟内存向物理内存的映射,也可以映射文件到自己的虚拟内存空间。映射文件时,实际是映射虚拟内存到物理内存再到文件。SYSCALLDEFINE6(mmap,unsignedlong,addr,unsignedlong,len,unsignedlong,prot,unsignedlong,flags,unsignedlong,fd,unsignedlong,off){errorEINVAL;if(offPAGEMASK)errorksysmmappgoff(addr,len,prot,flags,fd,offPAGESHIFT);out:}
  这里主要调用ksysmmappgoff()函数,这里逻辑如下:判断类型是否为匿名映射,如果不是则为文件映射,调用fget()获取文件描述符如果是匿名映射,判断是否为大页,如果是则进行对齐处理并调用hugetlbfilesetup()获取文件描述符调用vmmmappgoff()函数找寻可以映射的区域并建立映射unsignedlongksysmmappgoff(unsignedlongaddr,unsignedlonglen,unsignedlongprot,unsignedlongflags,unsignedlongfd,unsignedlongpgoff){structfilefileNULL;if(!(flagsMAPANONYMOUS)){auditmmapfd(fd,flags);filefget(fd);if(!file)returnEBADF;if(isfilehugepages(file))lenALIGN(len,hugepagesize(hstatefile(file)));retvalEINVAL;if(unlikely(flagsMAPHUGETLB!isfilehugepages(file)))}elseif(flagsMAPHUGETLB){structuserstructuserNULL;hshstatesizelog((flagsMAPHUGESHIFT)MAPHUGEMASK);if(!hs)returnEINVAL;lenALIGN(len,hugepagesize(hs));VMNORESERVEisusedbecausethereservationswillbetakenwhenvmopsmmap()iscalledAdummyuservalueisusedbecausewearenotlockingmemorysonoaccountingisnecessaryfilehugetlbfilesetup(HUGETLBANONFILE,len,VMNORESERVE,user,HUGETLBANONHUGEINODE,(flagsMAPHUGESHIFT)MAPHUGEMASK);if(ISERR(file))returnPTRERR(file);}flags(MAPEXECUTABLEMAPDENYWRITE);retvalvmmmappgoff(file,addr,len,prot,flags,pgoff);outfput:if(file)fput(file);}
  vmmmappgoff()函数调用dommappgoff(),实际调用dommap()函数。这里getunmappedarea()函数负责寻找可映射的区域,mmapregion()负责映射该区域。Thecallermustholddownwrite(tmmmmapsem)。unsignedlongdommap(structfilefile,unsignedlongaddr,unsignedlonglen,unsignedlongprot,unsignedlongflags,vmflagstvmflags,unsignedlongpgoff,unsignedlongpopulate,structlistheaduf){intpkey0;populate0;。。。。。。Obtaintheaddresstomapto。weverify(orselect)itandensurethatitrepresentsavalidsectionoftheaddressspace。addrgetunmappedarea(file,addr,len,pgoff,flags);。。。。。。addrmmapregion(file,addr,len,vmflags,pgoff,uf);if(!ISERRVALUE(addr)((vmflagsVMLOCKED)(flags(MAPPOPULATEMAPNONBLOCK))MAPPOPULATE))}
  更多Linux内核视频教程文本资料免费领取后台私信【内核大礼包】自行获取。
  首先来看看寻找映射区的函数getunmappedarea()。如果是匿名映射,则调用getumappedarea函数指针,这个函数其实是archgetunmappedarea()。它会调用findvmaprev(),在表示虚拟内存区域的vmareastruct红黑树上找到相应的位置。之所以叫prev,是说这个时候虚拟内存区域还没有建立,找到前一个vmareastruct。如果是映射到一个文件,在Linux里面每个打开的文件都有一个structfile结构,里面有一个fileoperations用来表示和这个文件相关的操作。如果是我们熟知的ext4文件系统,调用的也是getunmappedarea函数指针。unsignedlonggetunmappedarea(structfilefile,unsignedlongaddr,unsignedlonglen,unsignedlongpgoff,unsignedlongflags){unsignedlong(getarea)(structfile,unsignedlong,unsignedlong,unsignedlong,unsignedlong);unsignedlongerrorarchmmapcheck(addr,len,flags);if(error)Carefulaboutoverflows。。if(lenTASKSIZE)returnENOMEM;if(file){if(filefopgetunmappedarea)}elseif(flagsMAPSHARED){mmapregion()willcallshmemzerosetup()tocreateafile,souseshmemsgetunmappedareaincaseitcanbehuge。dommappgoff()willclearpgoff,somatchalignment。pgoff0;}addrgetarea(file,addr,len,pgoff,flags);if(ISERRVALUE(addr))if(addrTASKSIZElen)returnENOMEM;if(offsetinpage(addr))returnEINVAL;errorsecuritymmapaddr(addr);returnerror?error:}
  mmapregion()首先会再次检测地址空间是否满足要求,然后清除旧的映射,校验内存的可用性,在一切均满足的情况下调用vmalink()将新创建的vmareastruct结构挂在mmstruct内的红黑树上。unsignedlongmmapregion(structfilefile,unsignedlongaddr,unsignedlonglen,vmflagstvmflags,unsignedlongpgoff,structlistheaduf){structvmareastructvma,structrbnoderblink,unsignedlongcharged0;。。。。。。vmalink(mm,vma,prev,rblink,rbparent);Oncevmadenieswrite,undoourtemporarydenialcountif(file){if(vmflagsVMSHARED)mappingunmapwritable(filefmapping);if(vmflagsVMDENYWRITE)allowwriteaccess(file);}。。。。。。}
  vmalink()本身是vmalink()和vmalinkfile()的包裹函数staticvoidvmalink(structmmstructmm,structvmareastructvma,structvmareastructprev,structrbnoderblink,structrbnoderbparent){structaddressspacemappingNULL;if(vmavmfile){immaplockwrite(mapping);}vmalink(mm,vma,prev,rblink,rbparent);vmalinkfile(vma);if(mapping)immapunlockwrite(mapping);validatemm(mm);}
  其中vmalink()主要是链表和红黑表的插入,这属于基本数据结构操作,不展开讲解。staticvoidvmalink(structmmstructmm,structvmareastructvma,structvmareastructprev,structrbnoderblink,structrbnoderbparent){vmalinklist(mm,vma,prev,rbparent);vmalinkrb(mm,vma,rblink,rbparent);}
  而vmalinkfile()会对文件映射进行处理,在file结构体中成员fmapping指向addressspace结构体,该结构体中存储红黑树immap挂载vmareastruct。staticvoidvmalinkfile(structvmareastructvma){if(file){if(vmavmflagsVMDENYWRITE)atomicdec(fileinode(file)iwritecount);if(vmavmflagsVMSHARED)atomicinc(mappingimmapwritable);flushdcachemmaplock(mapping);vmaintervaltreeinsert(vma,mappingimmap);flushdcachemmapunlock(mapping);}}
  至此,我们完成了用户态内存的映射,但是此处仅在虚拟内存中建立了新的区域,尚未真正访问物理内存。物理内存的访问只有在调度到该进程时才会真正分配,即发生缺页异常时分配。
  三。用户态缺页异常一旦开始访问虚拟内存的某个地址,如果我们发现,并没有对应的物理页,那就触发缺页中断,调用dopagefault()。这里的逻辑如下判断是否为内核缺页中断faultinkernelspace(),如果是则调用vmallocfault()如果是用户态缺页异常,则调用findvma()找到地址所在vmareastruct区域调用handlemmfault()映射找到的区域Thisroutinehandlespagefaults。Itdeterminestheaddress,andtheproblem,andthenpassesitofftooneoftheappropriateroutines。asmlinkagevoidkprobesdopagefault(structptregsregs,unsignedlongerrorcode,unsignedlongaddress){。。。。。。Wefaultinkernelspacevirtualmemoryondemand。Thereferencepagetableisinitmm。pgd。NOTE!WeMUSTNOTtakeanylocksforthiscase。Wemaybeinaninterruptoracriticalregion,andshouldonlycopytheinformationfromthemasterpagetable,nothingmore。if(unlikely(faultinkernelspace(address))){if(vmallocfault(address)0)if(notifypagefault(regs,vec))badareanosemaphore(regs,errorcode,address);}。。。。。。vmafindvma(mm,address);。。。。。。Ifforanyreasonatallwecouldnthandlethefault,makesureweexitgracefullyratherthanendlesslyredothefault。faulthandlemmfault(vma,address,flags);。。。。。。}
  findvma()为红黑树查找操作,在此不做展开描述,下面重点看看handlemmfault()。这里经过一系列校验之后会根据是否是大页而选择调用hugetlbfault()或者handlemmfault()vmfaultthandlemmfault(structvmareastructvma,unsignedlongaddress,unsignedintflags){。。。。。。if(unlikely(isvmhugetlbpage(vma)))rethugetlbfault(vmavmmm,vma,address,flags);elserethandlemmfault(vma,address,flags);。。。。。。}
  handlemmfault()完成实际上的映射操作。这里涉及到了由pgd,p4g,pud,pmd,pte组成的五级页表,页表索引填充完后调用handleptefault()创建页表项。
  taticvmfaultthandlemmfault(structvmareastructvma,unsignedlongaddress,unsignedintflags){structvmfaultvmf{。vmavma,。addressaddressPAGEMASK,。flagsflags,。pgofflinearpageindex(vma,address),。gfpmaskgetfaultgfpmask(vma),};unsignedintdirtyflagsFAULTFLAGWRITE;p4dtp4d;pgdpgdoffset(mm,address);p4dp4dalloc(mm,pgd,address);。。。。。。vmf。pudpudalloc(mm,p4d,address);。。。。。。vmf。pmdpmdalloc(mm,vmf。pud,address);。。。。。。returnhandleptefault(vmf);}
  handleptefault()处理以下三种情况:页表项从未出现过,即新映射页表项匿名页映射,则映射到物理内存页,调用doanonymouspage()文件映射,调用dofault()页表项曾出现过,则为从物理内存换出的页,调用doswappage()换回来Theseroutinesalsoneedtohandlestufflikemarkingpagesdirtyandoraccessedforarchitecturesthatdontdoitinhardware(mostRISCarchitectures)。Theearlydirtyingisalsogoodonthei386。Thereisalsoahookcalledupdatemmucache()thatarchitectureswithexternalmmucachescanusetoupdatethose(ietheSparcorPowerPChashedpagetablesthatactasextendedTLBs)。Weenterwithnonexclusivemmapsem(toexcludevmachanges,butallowconcurrentfaults)。Themmapsemmayhavebeenreleaseddependingonflagsandourreturnvalue。Seefilemapfault()andlockpageorretry()。staticvmfaultthandleptefault(structvmfaultvmf){。。。。。。Aregularpmdisestablishedanditcantmorphintoahugepmdfromunderusanymoreatthispointbecauseweholdthemmapsemreadmodeandkhugepagedtakesitinwritemode。Sonowitssafetorunpteoffsetmap()。vmfptepteoffsetmap(vmfpmd,vmfaddress);。。。。。。if(!vmfpte){if(vmaisanonymous(vmfvma))returndoanonymouspage(vmf);elsereturndofault(vmf);}if(!ptepresent(vmforigpte))returndoswappage(vmf);。。。。。。}3。1匿名页映射
  对于匿名页映射,流程如下:调用ptealloc()分配页表项通过alloczeroeduserhighpagemovable()分配一个页,该函数会调用allocpagesvma(),并最终调用allocpagesnodemask()。该函数是伙伴系统的核心函数,用于分配物理页面,在上文中已经详细分析过了。调用mkpte()将新分配的页表项指向分配的页调用setpteat()将页表项加入该页Weenterwithnonexclusivemmapsem(toexcludevmachanges,butallowconcurrentfaults),andptemappedbutnotyetlocked。Wereturnwithmmapsemstillheld,butpteunmappedandunlocked。staticvmfaulttdoanonymouspage(structvmfaultvmf){vmfaulttret0;。。。。。。Useptealloc()insteadofpteallocmap()。Wecantrunpteoffsetmap()onpmdswhereahugepmdmightbecreatedfromadifferentthread。pteallocmap()issafetouseunderdownwrite(mmapsem)orwhenparallelthreadsareexcludedbyothermeans。Hereweonlyhavedownread(mmapsem)。if(ptealloc(vmavmmm,vmfpmd))returnVMFAULTOOM;。。。。。。pagealloczeroeduserhighpagemovable(vma,vmfaddress);。。。。。。entrymkpte(page,vmavmpageprot);if(vmavmflagsVMWRITE)entryptemkwrite(ptemkdirty(entry));vmfptepteoffsetmaplock(vmavmmm,vmfpmd,vmfaddress,vmfptl);。。。。。。setpteat(vmavmmm,vmfaddress,vmfpte,entry);。。。。。。}definealloczeroeduserhighpage(movableflags,vma,vaddr)allocpagevma(GFPHIGHUSERGFPZEROmovableflags,vma,vaddr)3。2文件映射
  映射文件dofault()函数调用了fault函数,该函数实际会根据不同的文件系统调用不同的函数,如ext4文件系统中vmops指向ext4filevmops,实际调用ext4filemapfault()函数,该函数会调用filemapfault()完成实际的文件映射操作。staticvmfaulttdofault(structvmfaultvmf){if(!vmavmopsfault){。。。。。。}vmfaulttext4filemapfault(structvmfaultvmf){。。。。。。retfilemapfault(vmf);。。。。。。}
  filemapfault()主要逻辑为:调用findgepage()找到映射文件vmfile对应的物理内存缓存页面如果找到了,则调用doasyncmmapreadahead(),预读一些数据到内存里面否则调用pagecachegetpage()分配一个缓存页,将该页加入LRU表中,并在addressspace中调用vmfaulttfilemapfault(structvmfaultvmf){structfilefpinNULL;。。。。。。Dowehavesomethinginthepagecachealready?pagefindgetpage(mapping,offset);if(likely(page)!(vmfflagsFAULTFLAGTRIED)){Wefoundthepage,sotryasyncreadaheadbeforewaitingforthelock。fpindoasyncmmapreadahead(vmf,page);}elseif(!page){Nopageinthepagecacheatall。。。。。。}structpagepagecachegetpage(structaddressspacemapping,pgofftoffset,intfgpflags,gfptgfpmask){。。。。。。pagepagecachealloc(gfpmask);。。。。。。erraddtopagecachelru(page,mapping,offset,gfpmask);。。。。。。}3。3页交换
  前文提到了我们会通过主动回收或者被动回收的方式将物理内存已映射的页面回收至硬盘中,当数据再次访问时,我们又需要通过doswappage()将其从硬盘中读回来。doswappage()函数逻辑流程如下:查找swap文件有没有缓存页。如果没有,就调用swapinreadahead()将swap文件读到内存中来形成内存页,并通过mkpte()生成页表项。setpteat将页表项插入页表,swapfree将swap文件清理。因为重新加载回内存了,不再需要swap文件了。vmfaulttdoswappage(structvmfaultvmf){。。。。。。entryptetoswpentry(vmforigpte);。。。。。。pagelookupswapcache(entry,vma,vmfaddress);if(!page){structswapinfostructsiswpswapinfo(entry);if(siflagsSWPSYNCHRONOUSIOswapcount(si,entry)1){skipswapcachepageallocpagevma(GFPHIGHUSERMOVABLE,vma,vmfaddress);。。。。。。}else{pageswapinreadahead(entry,GFPHIGHUSERMOVABLE,vmf);}。。。。。。ptemkpte(page,vmavmpageprot);。。。。。。setpteat(vmavmmm,vmfaddress,vmfpte,pte);archdoswappage(vmavmmm,vma,vmfaddress,pte,vmforigpte);。。。。。。swapfree(entry);。。。。。。}
  通过以上步骤,用户态的缺页异常就处理完毕了。物理内存中有了页面,页表也建立好了映射。接下来,用户程序在虚拟内存空间里面可以通过虚拟地址顺利经过页表映射的访问物理页面上的数据了。页表一般都很大,只能存放在内存中。操作系统每次访问内存都要折腾两步,先通过查询页表得到物理地址,然后访问该物理地址读取指令、数据。为了加快映射速度,我们引入了TLB(TranslationLookasideBuffer),我们经常称为快表,专门用来做地址映射的硬件设备。它不在内存中,可存储的数据比较少,但是比内存要快。所以我们可以想象,TLB就是页表的Cache,其中存储了当前最可能被访问到的页表项,其内容是部分页表项的一个副本。有了TLB之后,我们先查块表,块表中有映射关系,然后直接转换为物理地址。如果在TLB查不到映射关系时,才会到内存中查询页表。四。内核态内存映射及缺页异常
  和用户态使用malloc()类似,内核态也有相应的内存映射函数:vmalloc()可用于分配不连续物理页(使用伙伴系统),kmemcachealloc()和kmemcachecreate()使用slub分配器分配小块内存,而kmalloc()类似于malloc(),在分配大内存的时候会使用伙伴系统,分配小内存则使用slub分配器。分配内存后会转换为虚拟地址,保存在内核页表中进行映射,有需要时直接访问。由于vmalloc()会带来虚拟连续页和物理不连续页的映射,因此一般速度较慢,使用较少,相比而言kmalloc()使用的更为频繁。而kmemcachealloc()和kmemcachecreate()会分配更为精准的小内存块用于特定任务,因此也比较常用。
  相对于用户态,内核态还有一种特殊的映射:临时映射。内核态高端内存地区为了节省空间会选择临时映射,采用kmapatomic()实现。如果是32位有高端地址的,就需要调用setpte通过内核页表进行临时映射;如果是64位没有高端地址的,就调用pageaddress,里面会调用lowmempageaddress。其实低端内存的映射,会直接使用va进行临时映射。voidkmapatomicprot(structpagepage,pgprottprot){。。。。。。if(!PageHighMem(page))returnpageaddress(page);。。。。。。vaddrfixtovirt(FIXKMAPBEGINidx);setpte(kmappteidx,mkpte(page,prot));。。。。。。return(void)}voidkmapatomic(structpagepage){returnkmapatomicprot(page,kmapprot);}staticalwaysinlinevoidlowmempageaddress(conststructpagepage){returnpagetovirt(page);}definepagetovirt(x)va(PFNPHYS(pagetopfn(x)
  kmapatomic()发现没有页表的时候会直接创建页表进行映射。而vmalloc()只分配了内核的虚拟地址。所以访问它的时候,会产生缺页异常。内核态的缺页异常还是会调用dopagefault(),最终进入vmallocfault()。在这里会实现内核页表项的关联操作,从而完成分配,整体流程和用户态相似。staticnoinlineintvmallocfault(unsignedlongaddress){Makesureweareinvmallocarea:if(!(addressVMALLOCSTARTaddressVMALLOCEND))return1;Synchronizethistaskstoplevelpagetablewiththereferencepagetable。Donotusecurrenthere。Wemightbeinsideaninterruptinthemiddleofataskswitch。。pgdpaddrreadcr3pa();pmdkvmallocsyncone(va(pgdpaddr),address);if(!pmdk)return1;ptekpteoffsetkernel(pmdk,address);if(!ptepresent(ptek))return1;return0}五。总结
  至此,我们分析了内存物理地址和虚拟地址的映射关系,结合前文页的分配和管理,内存部分的主要功能就算是大致分析清楚了,最后引用极客时间中的一幅图作为总结,算是全部知识点的汇总。
  代码资料
  1、brk
  2、mmap
  3、pagefault
投诉 评论 转载

不想肝脏提前报废,这5件事坚持到底,保护好肝脏要避免肝脏受到损伤,许多好习惯得养成。部分人忽略保养的重要性,存在坏习惯后让器官功能降低,最后引发肝脏疾病,健康状态就无法保持。而肝脏疾病种类多,部分疾病还有继续发展的可能,如……我们是不是已经进入元宇宙有的时候感觉虚拟和现实分不清楚,感觉这个时代似乎已经是在元宇宙中。不信,你看。第一,有的时候感觉自己在一个场景中,无力改变任何事。第二,好久没摸过纸币了。钱只不过是一串数字,父……白发狂冒又掉发?营养师曝6种养发食物改善干枯易断变柔顺多补充头发头皮所需营养素,预防掉发、白发还能养出健康好发质。现代人工作生活忙碌、压力大,加上饮食、作息习惯改变,不少人都有掉发问题,甚至年纪轻轻就开始冒白发,发质也干枯、……重庆有一家1元面包馒头店,以前在洋人街,据说十几年没涨价这里是刘小顺的旅行和生活研究所。重庆是我国四大直辖市之一,因其独特的城市风貌以及人文特色而成为一座热门的网红旅游城市。因此,重庆有许多好玩的网红打卡点和网红店,都给……89岁老教授状告知网获赔70万不讲理!拿我的知识去赚钱文教育研说家知网一家独大,让多少学生和学者无奈但又无可奈何!知网是干什么的呢?想必大家还记得翟天临这个名字,当时有人问他,关于知网的问题。翟天临直接说,知网是……刘润边界感的本质,是对所有权的认知底层逻辑是润米咨询创始人、微软前战略合作总监、《5分钟商学院》主理人刘润提出的概念。他认为,只有掌握了环境背后的底层逻辑,探寻到了万变中的不变,才能在千变万化的世界中看清本质,……潮鞋NikeDunkLowHolidaySpecial蓝色情SeanCliverNikeDunkLowHolidaySpecial蓝色情人节冰雪奇缘潮鞋介绍:Bro,今天XLAB给你们带来这双SeanCliverNikeDunkL……闲情艺致儿童画到底有多美中国小康网独家专稿文沙子当你去看孩子们用心画的作品,不是这些作品有多么激动人心,而是你的心,是否真的有艺术感觉在跳跃和奔涌。带着我们自己的审美喜好,去尽情地欣赏和赞……在月球上能看见长城吗?每天一堂冷知识万里长城是我国最宏伟的建筑,是一道高大且坚固的长垣,总长超过了2。1万千米。为了展示长城的宏伟,很多人就说:万里长城是月球上能看到的唯一的地球建筑。那么在月球上是否真的能看见我……试用了4000元的健身镜,我选择退货开菠萝财经(kaiboluocaijing)原创作者唐亚华编辑黎明Letsgo,甩动手臂,打开胸口,向右走,转动臀部,反方向,再来一次小红书上,一位年轻女孩正……内存映射小块内存申请brk和申请大块内存的Mmap分析一。前言本文为内存部分最后一篇,介绍内存映射。内存映射不仅是物理内存和虚拟内存间的映射,也包括将文件中的内容映射到虚拟内存空间。这个时候,访问内存空间就能够访问到文件里面……乐视,这次真的活了除融创外华为、腾讯、京东、苏宁、TCL也都出力不少,乐视的后爸天团堪比豪门!乐视(三板400084),互联网界的一代妖姬,没死又活了!正当爱奇艺陷入巨额亏损,大幅缩减业务……
美丽的春天时间管理方法高效能人士必备技能两地造句用两地造句大全看样造句用看样造句大全霍华德惹谁了?体育媒体人还是得有点底线关于业务员试用期工作总结多篇科学家分离出古老僵尸病毒,距今48500年仍具感染性刚刚官宣!阜阳小丫邓琳琳被求婚分析公证融入多元化纠纷解决机制的价值目标和路径选空港经济腾飞城市投资正热后半生最长寿的活法(说得太好了)全球华人中餐馆经营成本大比拼爱情测试题测试他是不是只想和你搞暧昧竞争与合作教学反思范文英语作文孩子应不应该做家务安全合同家庭教育出现真空地带孩子成长过程父母缺席的危害暑假趣事的初中作文350字漫步完结之雨篇蓝海战略:专喂投机分子与懦夫的毒药政治面貌是什么意思感统失调真的长大了就好了吗?肖钢:大力推进监管转型善待自己

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找