chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

內(nèi)存剖析:從用戶態(tài)到內(nèi)核態(tài)內(nèi)存都做了什么?

Linux閱碼場(chǎng) ? 來(lái)源:Linux閱碼場(chǎng) ? 作者:Linux閱碼場(chǎng) ? 2023-01-06 11:04 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

編者按:本文順著c++關(guān)鍵字new向下,旨在分析介紹底層各層到底做了什么,為什么這么做。

1.c++用戶層

1.1提供的接口

1.1.1new

l 調(diào)用operator new 從自由存儲(chǔ)區(qū)分配一塊足夠大的內(nèi)存(sizeof(結(jié)構(gòu)))

l 調(diào)用相應(yīng)的構(gòu)造函數(shù)

l 構(gòu)造完成后返回指向該對(duì)象的指針

1.1.2delete

l 調(diào)用相應(yīng)的析構(gòu)函數(shù)

l 調(diào)用operator delete將內(nèi)存歸還給自由存儲(chǔ)區(qū)

1.1.3new數(shù)組

l 調(diào)用operator new[] 從自由存儲(chǔ)區(qū)分配一塊足夠大的內(nèi)存(sizeof(結(jié)構(gòu))+用區(qū)分對(duì)象數(shù)組指針和對(duì)象指針以及對(duì)象數(shù)組大小的額外數(shù)據(jù)),注意簡(jiǎn)單對(duì)象(即不需要構(gòu)造函數(shù)的類(lèi)型)將不會(huì)有額外數(shù)據(jù)的申請(qǐng)。

l 依次在內(nèi)存中調(diào)用相應(yīng)的構(gòu)造函數(shù)

l 構(gòu)造完成后返回指向該對(duì)象數(shù)組的起始地址,不包括前面的額外數(shù)據(jù)部分。

1.1.4delete數(shù)組

l 獲取數(shù)組起始地址前面的額外數(shù)據(jù),計(jì)算出數(shù)組長(zhǎng)度

l 根據(jù)數(shù)據(jù)長(zhǎng)度依次調(diào)用相應(yīng)的析構(gòu)函數(shù)

l調(diào)用operator delete將內(nèi)存歸還給自由存儲(chǔ)區(qū)

1.2operator new 的三種形式

形式1.void* operator new (std::size_t size)throw (std::bad_alloc);

形式2.void* operator new (std::size_t size,const std::nothrow_t& nothrow_value) throw();

形式3.void* operator new (std::size_t size,void* ptr) throw();

形式1跟形式2的區(qū)別僅僅是是否拋出異常,當(dāng)分配失敗時(shí),前者會(huì)拋出bad_alloc異常,后者返回NULL,不會(huì)拋出異常。它們都分配一個(gè)固定大小的連續(xù)內(nèi)存。

形式3又被稱(chēng)為placement new,它多接收一個(gè)ptr參數(shù),并且只是簡(jiǎn)單地返回該ptr。調(diào)用形式為 A* a=new(ptr)A()。在內(nèi)存池中有廣泛應(yīng)用,ptr即來(lái)自自由存儲(chǔ)區(qū),可以是堆、?;蛘哳A(yù)分配的內(nèi)存塊。

上述形式1和形式2都可以被重載,遵循作用域覆蓋原則,即在里向外尋找operator new的重載時(shí),只要找到operator new()函數(shù)就不再向外查找,如果參數(shù)符合則通過(guò),如果參數(shù)不符合則報(bào)錯(cuò),而不管全局是否還有相匹配的函數(shù)原型。

注意在形式1中,如果new分配異常,將拋出異常導(dǎo)致后續(xù)代碼不能被正常執(zhí)行。即如果在new操作后有解鎖操作,該解鎖操作將不會(huì)執(zhí)行導(dǎo)致死鎖。

1.3設(shè)定內(nèi)存分配失敗入口函數(shù)

poYBAGO3kQCAC5egAACcaTL7jkU638.jpg

1.4自由存儲(chǔ)區(qū)和堆的區(qū)別

從技術(shù)上來(lái)說(shuō),堆是C語(yǔ)言操作系統(tǒng)的術(shù)語(yǔ)。堆是操作系統(tǒng)所維護(hù)的一塊特殊內(nèi)存,它提供了動(dòng)態(tài)分配的功能,當(dāng)運(yùn)行程序調(diào)用malloc()時(shí)就會(huì)從中分配,稍后調(diào)用free可把內(nèi)存交還。而自由存儲(chǔ)是C++中通過(guò)new和delete動(dòng)態(tài)分配和釋放對(duì)象的抽象概念,通過(guò)new來(lái)申請(qǐng)的內(nèi)存區(qū)域可稱(chēng)為自由存儲(chǔ)區(qū)?;旧希械腃++編譯器默認(rèn)使用堆來(lái)實(shí)現(xiàn)自由存儲(chǔ),也即是缺省的全局運(yùn)算符new和delete也許會(huì)按照malloc和free的方式來(lái)被實(shí)現(xiàn),這時(shí)藉由new運(yùn)算符分配的對(duì)象,說(shuō)它在堆上也對(duì),說(shuō)它在自由存儲(chǔ)區(qū)上也正確。但程序員也可以通過(guò)重載操作符,改用其他內(nèi)存來(lái)實(shí)現(xiàn)自由存儲(chǔ),例如全局變量做的對(duì)象池,這時(shí)自由存儲(chǔ)區(qū)就區(qū)別于堆了。

我們只需要記?。憾咽遣僮飨到y(tǒng)維護(hù)的一塊內(nèi)存,而自由存儲(chǔ)是C++中通過(guò)new與delete動(dòng)態(tài)分配和釋放對(duì)象的抽象概念。堆與自由存儲(chǔ)區(qū)并不等價(jià)。這種區(qū)分大概是不同語(yǔ)言背景造成的。

1.5默認(rèn)內(nèi)存初始值

在vs2008(32bit)的debug模式下,由堆分配的內(nèi)存初始值為0xcdcd,中文“屯”;由棧分配的內(nèi)存初始值為0xcccc,中文“燙”。

1.6重載::operator new的理由

l 定位檢查代碼中內(nèi)存錯(cuò)誤

l 優(yōu)化內(nèi)存分配性能

l 獲得內(nèi)存使用統(tǒng)計(jì)數(shù)據(jù)

1.7重載::operator new的兩種方式

方式1:不改變簽名,替換系統(tǒng)現(xiàn)有版本

void* operator new(size_t size);

void operator delete(void* p);

使用方不需要包含任何特殊的頭文件,也就是說(shuō)不需要看見(jiàn)這兩個(gè)函數(shù)聲明。“性能優(yōu)化”通常用這種方式。

方式2:增加新參數(shù)

// 其返回的指針必須能被普通的 ::operator delete(void*) 釋放

void* operator new(size_t size, const char* file, int line);

Foo* p = new (__FILE, __LINE__) Foo;

也可以用宏替換 new 來(lái)節(jié)省打字。此種方式使用方需要看到這兩個(gè)函數(shù)聲明,也就是說(shuō)要主動(dòng)包含提供的頭文件?!皺z測(cè)內(nèi)存錯(cuò)誤”和“統(tǒng)計(jì)內(nèi)存使用情況”通常會(huì)用這種方式重載。

1.8重載::operator new的困境

1.8.1絕不能在library中重載::operator new

如果以上文提到的方式1來(lái)重載全局的::operator new,非常具有侵略性。使用該library的程序被迫使用了被重載的::operator new,并且一旦有另外的library也同樣重載了::operator new,就將會(huì)導(dǎo)致鏈接問(wèn)題。

那么如果采用上文提到的方式2來(lái)額外提供一個(gè)::operator new 版本呢,那就需要考慮重載后的::operator new 返回的指針能否被系統(tǒng)默認(rèn)的::operator delete釋放。如果不兼容系統(tǒng)則需要以方式1重載::operator new ,回到了上文提過(guò)的問(wèn)題。如果兼容,那么在新版本的::operator new中能做的事比較有限,比如不能額外申請(qǐng)內(nèi)存記錄統(tǒng)計(jì)信息,除非定義一個(gè)包含統(tǒng)計(jì)信息的基類(lèi)來(lái)作為所有申請(qǐng)對(duì)象的父類(lèi),但這樣就相當(dāng)于設(shè)定了開(kāi)發(fā)規(guī)范,稍有不注意可能就會(huì)出錯(cuò)。

1.8.2使用重載帶新參數(shù)的版本會(huì)有什么影響

如果使用方式1重載::operator new 使用起來(lái)似乎沒(méi)有什么問(wèn)題,但要考慮上節(jié)中提到的鏈接問(wèn)題。

如果使用方式2來(lái)重載::operator new,分成以下兩種場(chǎng)合。

對(duì)于以頭文件形式提供的library,可以在所有的cpp實(shí)現(xiàn)文件起始部分包含重載::operator new 的頭文件,但這具有侵略性。

對(duì)于以頭文件加二進(jìn)制庫(kù)提供的library,實(shí)際上帶新參數(shù)的版本并不會(huì)被這些庫(kù)使用。

1.9單獨(dú)為特定類(lèi)重載成員函數(shù)operator new怎么樣

與全局 ::operator new() 不同,per-class operator new() 和 operator delete () 的影響面要小得多,它只影響本 class 及其派生類(lèi)。似乎重載 member operator new() 是可行的。但是我并不贊同這種做法。

如果一個(gè)類(lèi)需要重載成員函數(shù)operator new(),說(shuō)明它用到了特殊的內(nèi)存分配策略,常見(jiàn)的情況是使用了內(nèi)存池或?qū)ο蟪?。寧愿把這一事實(shí)明顯地?cái)[出來(lái),而不是改變 new的默認(rèn)行為。

這可以歸結(jié)為最小驚訝原則:如果我們?cè)诖a里讀到 Node* p = new Node,通常我們會(huì)認(rèn)為它在堆上分配了內(nèi)存,如果 Node 類(lèi)重載了成員函數(shù)operator new(),那么就需要事先仔細(xì)閱讀 node.h 才能發(fā)現(xiàn)其實(shí)這行代碼使用了私有的內(nèi)存池。為什么不寫(xiě)得明確一點(diǎn)呢?如果寫(xiě)成Node*p = Node::createNode(),那么我們可能能猜到 Node::createNode() 肯定做了什么與 new不一樣的事情,免得將來(lái)大吃一驚。

1.10代替重載::operator new的方案

從glibc的malloc入手,替換掉malloc。具體方式參考tcmalloc中的override方式,點(diǎn)此鏈接[1]。

主要使用了gcc提供的alias別名屬性和weak屬性,我們能實(shí)現(xiàn)替換掉系統(tǒng)默認(rèn)的malloc原因在于系統(tǒng)提供的malloc系列函數(shù)都是被weak屬性修飾的。

對(duì)于全局函數(shù),如果沒(méi)有顯示修飾稱(chēng)weak屬性,那么他屬于強(qiáng)符號(hào);對(duì)于全局變量,已初始化完畢的屬于強(qiáng)符號(hào),沒(méi)有初始化完畢的則屬于弱符號(hào)。

有如下3點(diǎn)規(guī)則:

l 鏈接時(shí)強(qiáng)弱符號(hào)都存在時(shí)以強(qiáng)符號(hào)為準(zhǔn);

l 鏈接時(shí)如果只有弱符號(hào)時(shí)以弱符號(hào)為準(zhǔn);

l 鏈接時(shí)如兩個(gè)都是弱符號(hào),則以?xún)?nèi)存占用大小較大的那個(gè)符號(hào)為準(zhǔn);

2.glibc層

2.1概述

實(shí)際上glibc采用了一種批發(fā)和零售的方式來(lái)管理內(nèi)存。glibc每次通過(guò)系統(tǒng)調(diào)用的方式申請(qǐng)一大塊內(nèi)存(虛擬內(nèi)存),當(dāng)進(jìn)程申請(qǐng)內(nèi)存時(shí),glibc就從自己獲得的內(nèi)存中取出一塊給進(jìn)程。

glibc對(duì)于heap內(nèi)存申請(qǐng)大于128k的內(nèi)存申請(qǐng),glibc采用mmap的方式向內(nèi)核申請(qǐng)內(nèi)存,也就是此時(shí)的malloc是由mmap來(lái)實(shí)現(xiàn)的,這不能保證內(nèi)存地址向上增長(zhǎng);小于128k的則采用brk,malloc調(diào)用系統(tǒng)調(diào)用brk來(lái)實(shí)現(xiàn)向內(nèi)核批發(fā)虛擬內(nèi)存,對(duì)于它來(lái)講是正確的。128k的閥值,可以通過(guò)glibc的庫(kù)函數(shù)進(jìn)行設(shè)置。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 內(nèi)核
    +關(guān)注

    關(guān)注

    4

    文章

    1436

    瀏覽量

    42494
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    9

    文章

    3173

    瀏覽量

    76118
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4406

    瀏覽量

    66847
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2122

    瀏覽量

    76714

原文標(biāo)題:內(nèi)存剖析:從用戶態(tài)到內(nèi)核態(tài)內(nèi)存都做了什么?

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    Linux 內(nèi)存管理知識(shí)學(xué)習(xí)經(jīng)驗(yàn)總結(jié)

    內(nèi)核態(tài)用戶態(tài)兩部分,經(jīng)典比例如下:用戶態(tài)
    發(fā)表于 02-25 17:08

    Linux內(nèi)核態(tài)下如何讀寫(xiě)IIC

    目前在Linux3.12上,想在內(nèi)核態(tài)下讀取LM75溫度傳感器的溫度值,做了如下操作,但是讀數(shù)據(jù)的時(shí)候i2c_transfer一直報(bào)錯(cuò)。先將LM75設(shè)備掛到IIC總線上:在sys下可以發(fā)現(xiàn)已經(jīng)添加成功:但是讀數(shù)據(jù)的時(shí)候就一直報(bào)錯(cuò)
    發(fā)表于 11-29 19:07

    Linux內(nèi)存系統(tǒng):內(nèi)存使用場(chǎng)景

    文件映射、共享內(nèi)存)· 程序的內(nèi)存 map(棧、堆、code、data)· 內(nèi)核用戶態(tài)的數(shù)據(jù)傳遞(copy_from_user、copy
    發(fā)表于 08-25 07:42

    Linux內(nèi)存系統(tǒng)---走進(jìn)Linux 內(nèi)存

    內(nèi)存區(qū)域· MMAP:共享庫(kù)及匿名文件的映射區(qū)域· STACK:用戶進(jìn)程棧7、內(nèi)核態(tài)地址空間 · 直接映射區(qū):線性空間中 3G 開(kāi)始最大
    發(fā)表于 08-26 08:05

    操作系統(tǒng)為什么分內(nèi)核態(tài)用戶態(tài)?這兩者如何切換?

    操作系統(tǒng)為什么分內(nèi)核態(tài)用戶態(tài),這兩者如何切換?進(jìn)程在地址空間會(huì)劃分為哪些區(qū)域?堆和棧有什么區(qū)別?
    發(fā)表于 07-23 09:01

    請(qǐng)問(wèn)CPU與寄存器,內(nèi)核態(tài)用戶態(tài)及如何切換?

    計(jì)算機(jī)硬件系統(tǒng)由哪幾部分構(gòu)成?編程語(yǔ)言的作用及與操作系統(tǒng)和硬件的關(guān)系是什么?請(qǐng)問(wèn)CPU與寄存器,內(nèi)核態(tài)用戶態(tài)及如何切換?
    發(fā)表于 10-25 06:31

    OpenHarmony喂狗源碼解讀之用戶態(tài)源碼

    timeout\n"); } else {// 用戶態(tài)設(shè)置喂狗超時(shí)時(shí)間為大于gap 用戶態(tài)喂狗間隔時(shí)間為// 獲取內(nèi)核的超時(shí)間 - gap
    發(fā)表于 01-26 10:57

    鴻蒙內(nèi)核實(shí)現(xiàn)用戶態(tài)快速互斥鎖Futex設(shè)計(jì)資料合集

    Futex(Fast userspace mutex,用戶態(tài)快速互斥鎖),系列篇簡(jiǎn)稱(chēng) 快鎖 ,是一個(gè)在 Linux 上實(shí)現(xiàn)鎖定和構(gòu)建高級(jí)抽象鎖如信號(hào)量和POSIX互斥的基本工具,它第一次出現(xiàn)在
    發(fā)表于 03-23 14:12

    Linux虛擬內(nèi)存和物理內(nèi)存的深刻分析

    內(nèi)存,用戶進(jìn)程總是先獲得一個(gè)虛擬內(nèi)存區(qū)的使用權(quán),最終通過(guò)缺頁(yè)異常獲得一塊真正的物理內(nèi)存。物理內(nèi)存內(nèi)核
    發(fā)表于 05-31 08:00

    一個(gè)內(nèi)核態(tài)Key-Value存儲(chǔ)系統(tǒng)

    的數(shù)據(jù)存儲(chǔ)需求中尤為突出。針對(duì)該問(wèn)題,給出了一個(gè)內(nèi)核態(tài)Key-Value存儲(chǔ)系統(tǒng)的實(shí)現(xiàn)-KStore:提供內(nèi)核空間的索引和內(nèi)存分配機(jī)制,并在此基礎(chǔ)上,通過(guò)基于
    發(fā)表于 01-19 16:37 ?0次下載
    一個(gè)<b class='flag-5'>內(nèi)核</b><b class='flag-5'>態(tài)</b>Key-Value存儲(chǔ)系統(tǒng)

    詳解Linux的物理內(nèi)存

    內(nèi)核態(tài)申請(qǐng)內(nèi)存比在用戶態(tài)申請(qǐng)內(nèi)存要更為直接,它沒(méi)有采用用戶
    的頭像 發(fā)表于 01-18 17:45 ?2757次閱讀
    詳解Linux的物理<b class='flag-5'>內(nèi)存</b>

    Linux內(nèi)核態(tài)缺頁(yè)會(huì)發(fā)生什么 - 玩轉(zhuǎn)Exception fixup表

    Linux內(nèi)核的做法是提供了一張 異常處理表 ,使用專(zhuān)有的函數(shù)來(lái)訪問(wèn)用戶態(tài)內(nèi)存。類(lèi)似 try-catch塊一般。具體詳情可參見(jiàn)copy_to_user/copy_from_user的實(shí)
    的頭像 發(fā)表于 06-03 15:08 ?3303次閱讀

    探究slab在內(nèi)核內(nèi)存管理和用戶態(tài)Memcached的雙重存在

    ,但是作為內(nèi)核的堆用戶本身,經(jīng)常只是調(diào)用kmalloc()申請(qǐng)一個(gè)小內(nèi)存,或者調(diào)用kmem_cache_alloc()申請(qǐng)一個(gè)數(shù)據(jù)結(jié)構(gòu),2^n頁(yè)給它,會(huì)形成大量碎片浪費(fèi)。所以slab找buddy要了2
    的頭像 發(fā)表于 08-13 14:55 ?1931次閱讀
    探究slab在<b class='flag-5'>內(nèi)核</b><b class='flag-5'>內(nèi)存</b>管理和<b class='flag-5'>用戶</b><b class='flag-5'>態(tài)</b>Memcached的雙重存在

    Linux內(nèi)核用戶態(tài)是如何睡眠的

    clock_nanosleep系統(tǒng)調(diào)用來(lái)進(jìn)行睡眠(也就是說(shuō)用戶態(tài)任務(wù)睡眠需要調(diào)用系統(tǒng)調(diào)用陷入內(nèi)核)。 下面我們來(lái)研究下clock_nanosleep的實(shí)現(xiàn)(這里集中睡眠的實(shí)現(xiàn),先忽略
    的頭像 發(fā)表于 08-16 15:06 ?2616次閱讀

    如何實(shí)現(xiàn)一個(gè)高性能內(nèi)存

    ,按照慣例先說(shuō)內(nèi)存池的應(yīng)用場(chǎng)景。 為什么我們需要內(nèi)存池? 因?yàn)閙alloc等分配內(nèi)存的方式,需要涉及系統(tǒng)調(diào)用sbrk,頻繁的malloc和free會(huì)消耗系統(tǒng)資源。 既然如此,我們就預(yù)
    的頭像 發(fā)表于 11-10 11:11 ?1218次閱讀
    如何實(shí)現(xiàn)一個(gè)高性能<b class='flag-5'>內(nèi)存</b>池