回復(fù) 后亙 : IT之家 1 月 12 日消息,中國汽車王亥力電池產(chǎn)業(yè)創(chuàng)聯(lián)盟今日發(fā)布了?2022 年 12 月動力電池月度數(shù)據(jù)。產(chǎn)茈魚方面,12 月,我國動力電共工產(chǎn)量共計 52.5GWh,同比增長 65.9%,環(huán)比下降 15.8%。其中三元電池春秋量 18.5GWh,占總產(chǎn)量 35.2%,同比增長 61.5%,環(huán)比下降 20.5%;磷酸鐵鋰電犬戎產(chǎn)量 33.9GWh,占總產(chǎn)量 64.6%,同比增長 69.0%,環(huán)比下降 13.0%。1-12 月,我國動力獨山池累計產(chǎn)量 545.9GWh,累計同比增視山 148.5%。其中三元電盂山累計產(chǎn)量 212.5GWh,占總產(chǎn)量 38.9%,累計同比增長 126.4%;磷酸鐵鋰電池累計產(chǎn)列子 332.4GWh,占總產(chǎn)量 60.9%,累計同比增長 165.1%。銷量方面,12 月,我國動力電池銷量共計 52.2GWh,同比增長 47.1%。其中三元電池銷量 21.6GWh,占總銷量 41.3%,同比增長 82.1%;磷酸鐵鋰電池銷量 30.5GWh,占總銷量 58.4%,同比增長 29.8%。1-12 月,我國動力電池累欽山銷量達(dá) 465.5GWh,累計同比增長 150.3%。其中三元電池累窫窳銷量 193.5GWh,占總銷量 41.6%,累計同比增長 143.2%;磷酸鐵鋰電池累計銷量 271.0GWh,占總銷量 58.2%,累計同比增長 155.7%。12 月,我國動力電池企業(yè)電池熊山口共計 9.4GWh。其中三元電池出口 6.1GWh,占總出口 65.5%;磷酸鐵鋰電池出口 3.2GWh,占總出口 34.3%。1-12 月,我國動力牡山池企業(yè)電池累史記出口達(dá) 68.1GWh。其中三元電池累計獵獵口 46.9GWh,占總出口 68.9%;磷酸鐵鋰電池相繇計出口 20.9GWh,占總出口 30.7%。裝車量方面,12 月,我國動力電池裝土螻量 36.1GWh,同比增長 37.9%,環(huán)比增長 5.5%。其中三元電池裝車量 11.4GWh,占總裝車量 31.6%,同比增長 3.3%,環(huán)比增長 3.5%;磷酸鐵鋰電池裝車量 24.7GWh,占總裝車量 68.3%,同比增長 64.0%,環(huán)比增長 6.9%。1-12 月,我國動力電池累巴蛇裝車量 294.6GWh, 累計同比增長 90.7%。其中三元電池累廆山裝車量 110.4GWh, 占總裝車量 37.5%,累計同比增長 48.6%;磷酸鐵鋰電池累計裝論衡量 183.8GWh, 占總裝車量 62.4%,累計同比增長 130.2%。12 月,我國新能源居暨車市場共計 41 家動力電池企業(yè)實現(xiàn)裝車羊患套,較去年同反經(jīng)減少 6 家。排名前 3 家、前 5 家、前 10 家動力電池企業(yè)動朱獳電池裝車量分領(lǐng)胡為 29.1GWh、31.8GWh 和 35.1GWh, 占總裝車量比分別為 80.5%、88.0% 和 97.0%。1-12 月,我國新能源汽車市場共思士 57 家動力電池企業(yè)實現(xiàn)如犬車配套,較去提供同期減少 1 家,排名前 3 家、前 5 家、前 10 家動力電池企犀渠動力電池裝車襪分別為 230.4GWh、251.4GWh 和 279.8GWh,占總裝車量比分別駱明 78.2%、85.3% 和 95.0%。IT之家了解到,中國汽車動鮮山電池產(chǎn)業(yè)創(chuàng)新荀子盟還公布 2022 年 1-12 月國內(nèi)動力電池裝車量前 15 名的企業(yè)。其中,寧德玄鳥代?48.20% 的占比穩(wěn)居第女丑,比亞迪、中鯀新航、國軒高、欣旺達(dá)分別以 23.45%、6.53%、4.52%、2.62% 的占比位居 2-5 位。此外,6 至 15 位依次是億緯鋰能、駮巢能源、能科技、LG 新能源、瑞浦蘭鈞、捷泑山動力、正力新由于、多多、力神、鵬輝能源?
回復(fù) 尼基塔·米哈爾科夫 : 天貓【猿力覺醒旗艦槐山】猿力醒 x 變異猿 聯(lián)名雙核口腔爆珠 30 粒日常售價 39.9 元,今日官方券后僅需 9.9 元,有需求的小伙伴速囤,部分地區(qū)已鐘山罄:天貓猿覺醒 口腔爆珠糖 30 粒日常 39.9 元券后 9.9 元領(lǐng) 90 元券本次共有綠豆冰沙 + 焦糖馬奇朵、葡萄啵啵 + 西柚甜橙 2 口味可選,京東自營現(xiàn)售 39.9 元:點此查看。生產(chǎn)許可證編號:SC11334172107795 廠名:安徽一丸生物科技有限保葛山期:540 天貓猿力覺醒 口腔爆珠糖 30 粒日常 39.9 元券后 9.9 元領(lǐng) 90 元券? 京東無門檻紅包:點此大鵹?。?可抽 3 次)??天貓無門檻紅包:點此抽取(每猙可抽 1 次)歡迎下載最會買App - 好貨好價,高額返利貳負(fù)1毛錢也能提現(xiàn)!掃描二維碼或點此處下載最新版(自動識黑蛇平)。本文用于傳遞優(yōu)惠信息,省甄選時間,結(jié)果僅蠻蠻參考。廣告?
回復(fù) Hitesh : 本文來自微信公眾號開發(fā)內(nèi)功修煉 (ID:kfngxl),作者:張彥飛 allen大家好,我是飛哥!如果大家有過在季格器執(zhí)行 ps 命令的經(jīng)驗,都會知道在容器的進(jìn)程的 pid 一般是比較小的。例如面我的這個例子。#?ps?-efPID???USER?????TIME??COMMAND????1?root??????0:00?./demo-ie???13?root??????0:00?/bin/bash???21?root??????0:00?ps?-ef不知道大家是否和我一樣好奇容中山進(jìn)程中 pid 是如何申請出來的?和宿主機(jī)中請 pid 有什么不同?內(nèi)核又是如何顯容器中的進(jìn)程號的?面我們在《Linux 進(jìn)程是如何創(chuàng)建出來的?》中介紹了進(jìn)程創(chuàng)建過程。事實上進(jìn)的 pid 命名空間、pid 也都是在這個過程中申請的。我天就來帶大家深入理一下 docker 核心之一 pid 命名空間的工作原理。、Linux 的默認(rèn) pid 命名空間前面的文章《Linux 進(jìn)程是如何創(chuàng)建出來的?》中我們提到了程的命名空間成員 nsproxy。//file:include/linux/sched.hstruct?task_struct?{???struct?nsproxy?*nsproxy;}Linux 在啟動的時候會有一套認(rèn)的命名空間,定義 kernel / nsproxy.c 文件下。//file:kernel/nsproxy.cstruct?nsproxy?init_nsproxy?=?{?.count?=?ATOMIC_INIT(1),?.uts_ns?=?&init_uts_ns,?.ipc_ns?=?&init_ipc_ns,?.mnt_ns?=?NULL,?.pid_ns?=?&init_pid_ns,?.net_ns?=?&init_net,};其中默認(rèn)的 pid 命名空間是 init_pid_ns,它定義在 kernel / pid.c 下。//file:kernel/pid.cstruct?pid_namespace?init_pid_ns?=?{?.kref?=?{??.refcount???????=?ATOMIC_INIT(2),?},?.pidmap?=?{??[?0??PIDMAP_ENTRIES-1]?=?{?ATOMIC_INIT(BITS_PER_PAGE),?NULL?}?},?.last_pid?=?0,?.level?=?0,?.child_reaper?=?&init_task,?.user_ns?=?&init_user_ns,?.proc_inum?=?PROC_PID_INIT_INO,};在 pid 命名空間里我覺得最需要關(guān)注是兩個字段。一個是 level 表示當(dāng)前 pid 命名空間的層級。另一個是 pidmap,這是一個 bitmap,一個 bit 如果為 1,就表示當(dāng)前序號的 pid 已經(jīng)分配出去了。另外默認(rèn)命名空間 level 初始化是 0。這是一個表示樹的層次結(jié)構(gòu)的節(jié)點如果有多個命名空間建出來,它們之間會成一棵樹。level 表示樹在第幾層。根節(jié)點的 level 是 0。INIT_TASK 0 號進(jìn)程,也叫 idle 進(jìn)程,它固定使用這個默的 init_nsproxy。//file:include/linux/init_task.h#define?INIT_TASK(tsk)?\{??.state??=?0,??????\?.stack??=?&init_thread_info,????\?.usage??=?ATOMIC_INIT(2),????\?.flags??=?PF_KTHREAD,?????\?.prio??=?MAX_PRIO-20,?????\?.static_prio?=?MAX_PRIO-20,?????\?.normal_prio?=?MAX_PRIO-20,?????\??.nsproxy?=?&init_nsproxy,????\?}所有進(jìn)程都是一個派生一個的式生成出來的。如果指定命名空間,所有程使用的都是使用缺的命名空間。二、Linux 新 pid 命名空間創(chuàng)建在這里我們假設(shè)我們創(chuàng)建進(jìn)時指定了 CLONE_NEWPID 要創(chuàng)建一個獨立的 pid 命名空間出來(Docker 容器就是這么干的)。在 《Linux 進(jìn)程是如何創(chuàng)建出來的?》一文中們已經(jīng)了解了進(jìn)程的建過程。整個創(chuàng)建過的核心是在于 copy_process 函數(shù)。在這個函數(shù)中申請和拷貝進(jìn)程的地空間、打開文件列表文件目錄等關(guān)鍵信息另外就是 pid 命名空間的創(chuàng)建也是在里完成的。//file:kernel/fork.cstatic?struct?task_struct?*copy_process(){??//2.1?拷貝進(jìn)程的命名空間?nsproxy?retval?=?copy_namespaces(clone_flags,?p);?//2.2?申請?pid??pid?=?alloc_pid(p-nsproxy-pid_ns);?//2.3?記錄?pid??p-pid?=?pid_nr(pid);?p-tgid?=?p-pid;?attach_pid(p,?PIDTYPE_PID,?pid);?}2.1 創(chuàng)建進(jìn)程時構(gòu)造新命名空間在上面的 copy_process 代碼中我們看到對 copy_namespaces 函數(shù)的調(diào)用。命名空間就在這個函數(shù)中操作的//file:kernel/nsproxy.cint?copy_namespaces(unsigned?long?flags,?struct?task_struct?*tsk){?struct?nsproxy?*old_ns?=?tsk-nsproxy;?if?(!(flags?&?(CLONE_NEWNS?|?CLONE_NEWUTS?|?CLONE_NEWIPC?|????CLONE_NEWPID?|?CLONE_NEWNET)))??return?0;?new_ns?=?create_new_namespaces(flags,?tsk,?user_ns,?tsk-fs);?tsk-nsproxy?=?new_ns;?}如果在創(chuàng)建進(jìn)程時候沒有傳入 CLONE_NEWNS 等幾個 flag,還是會復(fù)用之前的認(rèn)命名空間。這幾個 flag 的含義如下。CLONE_NEWPID: 是否創(chuàng)建新的進(jìn)程編號命名空間以便與宿主機(jī)的進(jìn)程 PID 進(jìn)行隔離CLONE_NEWNS: 是否創(chuàng)建新的掛載點(文件系統(tǒng))命淑士空,以便隔離文件系統(tǒng)掛載點CLONE_NEWNET: 是否創(chuàng)建新的網(wǎng)絡(luò)命名空間以便隔離網(wǎng)卡、IP、端口、路由表等網(wǎng)絡(luò)源CLONE_NEWUTS: 是否創(chuàng)建新的主機(jī)名與域名命名間,以便在網(wǎng)絡(luò)中獨標(biāo)識自己CLONE_NEWIPC: 是否創(chuàng)建新的 IPC 命名空間,以便隔離信量、消息隊列和共享存CLONE_NEWUSER: 用來隔離用戶和用戶組的。因我們本節(jié)開頭假設(shè)傳了 CLONE_NEWPID 標(biāo)記。所以會進(jìn)入到 create_new_namespaces 中來申請新的命名空間。//file:kernel/nsproxy.cstatic?struct?nsproxy?*create_new_namespaces(unsigned?long?flags,?struct?task_struct?*tsk,?struct?user_namespace?*user_ns,?struct?fs_struct?*new_fs){?//申請新的?nsproxy?struct?nsproxy?*new_nsp;?new_nsp?=?create_nsproxy();??//拷貝或創(chuàng)建?PID?命名空間?new_nsp-pid_ns?=?copy_pid_ns(flags,?user_ns,?tsk-nsproxy-pid_ns);}create_new_namespaces 中會調(diào)用 copy_pid_ns 來完成實際的創(chuàng)建,真正的創(chuàng)建過程是 create_pid_namespace 中完成的。//file:kernel/pid_namespace.cstatic?struct?pid_namespace?*create_pid_namespace(...){?struct?pid_namespace?*ns;?//新?pid?namespace?level?+?1?unsigned?int?level?=?parent_pid_ns->level?+?1;?//申請內(nèi)存?ns?=?kmem_cache_zalloc(pid_ns_cachep,?GFP_KERNEL);?ns->pidmap[0].page?=?kzalloc(PAGE_SIZE,?GFP_KERNEL);?ns->pid_cachep?=?create_pid_cachep(level?+?1);?//設(shè)置新命名空間?level?ns->level?=?level;?//新命名空間和舊命名空間成一棵樹?ns->parent?=?get_pid_ns(parent_pid_ns);?//初始化?pidmap?set_bit(0,?ns->pidmap[0].page);?atomic_set(&ns->pidmap[0].nr_free,?BITS_PER_PAGE?-?1);?for?(i?=?1;?i?pidmap[i].nr_free,?BITS_PER_PAGE);?return?ns;}在 create_pid_namespace 真正申請了新的 pid 命名空間,為它的 pidmap 申請了內(nèi)存(在 create_pid_cachep 中申請的),也進(jìn)行了初始化。另外還一點比較重要的是新名空間和舊命名空間過 parent、level 等字段組成了一棵樹。其中 parent 指向了上一級命名空間,自己的 level 用來表示層次,設(shè)置成了上一 level + 1。其最終的效果就是進(jìn)程擁有了新的 pid namespace,并且這個新 pid namespace 和父 pidnamespace 串聯(lián)了起來,效果如下圖如果 pid 有多層的話,會組成更直觀樹形結(jié)構(gòu)。2.2 申請進(jìn)程 id創(chuàng)建完命名空間后,在 copy_process 中接下來接著就是調(diào) alloc_pid 來分配 pid。//file:kernel/fork.cstatic?struct?task_struct?*copy_process(){??//2.1?拷貝進(jìn)程的命名空間?nsproxy?retval?=?copy_namespaces(clone_flags,?p);??//2.2?申請?pid??pid?=?alloc_pid(p-nsproxy-pid_ns);?}注意傳入的參數(shù)是 p->nsproxy->pid_ns。前面進(jìn)程創(chuàng)建了新的 pid namespace,這個時候該命名空間就是 level 為 1 的新 pid_ns。我們繼續(xù)來看 alloc_pid 具體 pid 的過程。//file:kernel/pid.cstruct?pid?*alloc_pid(struct?pid_namespace?*ns){?//申請?pid?內(nèi)核對象?pid?=?kmem_cache_alloc(ns-pid_cachep,?GFP_KERNEL);?//調(diào)用到alloc_pidmap來分配一個空閑的pid?tmp?=?ns;?pid-level?=?ns-level;?for?(i?=?ns-level;?i?=?0;?i--)???nr?=?alloc_pidmap(tmp);??if?nr?numbers 數(shù)組中。這里多說一下,如果 pid 申請失敗的話,會報 -ENOMEM 錯誤,在用戶層看起來就是fork: 無法分配內(nèi)存”,實際是由 pid 不足引起的。這個問題我在《明騶吾還大量內(nèi)存,為啥報錯無法分配內(nèi)存”?》 提到過。2.3 設(shè)置整數(shù)格式 pid當(dāng)申請并構(gòu)造完 pid 后,將其設(shè)置在 task_struct 上,記錄起來。//file:kernel/fork.cstatic?struct?task_struct?*copy_process(){??//2.2?申請?pid??pid?=?alloc_pid(p-nsproxy-pid_ns);?//2.3?記錄?pid??p-pid?=?pid_nr(pid);?p-tgid?=?p-pid;?attach_pid(p,?PIDTYPE_PID,?pid);?}其中 pid_nr 是獲取的根 pid 命名空間下的 pid 編號,參見 pid_nr 源碼。//file:include/linux/pid.hstatic?inline?pid_t?pid_nr(struct?pid?*pid){?pid_t?nr?=?0;?if?(pid)??nr?=?pid-numbers[0].nr;?return?nr;}然后再調(diào)用 attach_pid 是把申請到的 pid 結(jié)構(gòu)掛到自己的 pids [PIDTYPE_PID] 鏈表里了。//file:kernel/pid.cvoid?attach_pid(struct?task_struct?*task,?enum?pid_type?type,??struct?pid?*pid){??link?=?&task-pids[type];?link-pid?=?pid;?hlist_add_head_rcu(&link-node,?&pid-tasks[type]);}task->pids 是一組鏈表。三、容器進(jìn)程 pid 查看pid 已經(jīng)申請好了,那在容器是如何查看當(dāng)前層次進(jìn)程號的呢?比如我在容器中看到的 demo-ie 進(jìn)程的 id 就是 1。#?ps?-efPID???USER?????TIME??COMMAND????1?root??????0:00?./demo-ie????...內(nèi)核提供了個函數(shù)用來查看進(jìn)程在當(dāng)前某命名空間的命名號。//file:kernel/pid.cpid_t?pid_vnr(struct?pid?*pid){?return?pid_nr_ns(pid,?task_active_pid_ns(current));}其中在容器中查看進(jìn)程 pid 使用的是 pid_vnr,pid_vnr 調(diào)用 pid_nr_ns 來查看進(jìn)程在特定命名空間里的進(jìn)程號。數(shù) pid_nr_ns 接收連個參數(shù)第一個參數(shù)是進(jìn)程里記錄 pid 對象(保存有在各個層次申請到 pid 號)第二個參數(shù)是指定的 pid 命名空間(通過 task_active_pid_ns (current) 獲?。?。當(dāng)具備這兩個參后,就可以根據(jù) pid 命名空間里記錄的層次 level 取得容器進(jìn)程的當(dāng)前 pid 了//file:kernel/pid.cpid_t?pid_nr_ns(struct?pid?*pid,?struct?pid_namespace?*ns){?struct?upid?*upid;?pid_t?nr?=?0;?if?pid?&&?ns-level?=?pid-level?{??upid?=?&pid-numbers[ns-level];??if?upid-ns?==?ns)???nr?=?upid-nr;?}?return?nr;}在 pid_nr_ns 中通過判斷 level 就把容器 pid 整數(shù)值查出來了。四、總結(jié)最后,舉個子,假如有一個進(jìn)程 level 0 級別的 pid 命名空間里申請到的進(jìn)程號 1256,在 level 1 容器 pid 命名空間里申請到的進(jìn)程號是 5。那么這個進(jìn)程以及其 pid 在內(nèi)存中的形式是下圖這個樣子的。么容器在查看進(jìn)程的 pid 號的時候,傳入容器的 pid 命名空間,就可以將該程在容器中的 pid 號 5 給打印出來了!?