oom killer
該機(jī)制會(huì)監(jiān)控那些占用內(nèi)存過(guò)大,尤其是瞬間很快消耗大量?jī)?nèi)存的進(jìn)程,為了防止內(nèi)存耗盡會(huì)把該進(jìn)程殺掉。
Linux在內(nèi)存分配路徑上會(huì)對(duì)內(nèi)存余量做檢查,(1)如果檢查到內(nèi)存不足,則觸發(fā)OOM機(jī)制。(2)OOM首先會(huì)對(duì)系統(tǒng)所有進(jìn)程(出init和內(nèi)核線程等特殊進(jìn)程)進(jìn)行打分,并選出最bad的進(jìn)程;然后殺死該進(jìn)程。(3)同時(shí)會(huì)觸發(fā)內(nèi)核oom_reaper進(jìn)行內(nèi)存收割。(4)同時(shí)內(nèi)核還提供了sysfs接口系統(tǒng)OOM行為,以及進(jìn)程O(píng)OM行為。然后借用一個(gè)示例來(lái)分析OOM時(shí)內(nèi)存狀態(tài)。
1. 關(guān)于OOM
內(nèi)核檢測(cè)到系統(tǒng)內(nèi)存不足,在內(nèi)存分配路徑上觸發(fā) out_of_memory() ,然后調(diào)用 select_bad_process() 選擇一個(gè)'bad'進(jìn)程 oom_kill_process() 殺掉,判斷和選擇一個(gè)‘bad'進(jìn)程的過(guò)程由 oom_badness() 決定。
Linux下每個(gè)進(jìn)程都有自己的OOM權(quán)重,在/proc/<pid>/oom_adj里面,范圍是-17到+15,取值越高,越容易被殺掉。
2. OOM觸發(fā)路徑
在內(nèi)存分配路徑上,當(dāng)內(nèi)存不足的時(shí)候會(huì)觸發(fā)kswapd、或者內(nèi)存規(guī)整,極端情況會(huì)觸發(fā)OOM,來(lái)獲取更多內(nèi)存。
在內(nèi)存回收失敗之后,__alloc_pages_may_oom是OOM的入口,但是主要工作在out_of_memory中進(jìn)行處理。
由于Linux內(nèi)存都是以頁(yè)為單位,所以__alloc_pages_nodemask是必經(jīng)之處。
static inline struct page *
__alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
const struct alloc_context *ac, unsigned long *did_some_progress)
{
struct oom_control oc = {---------------------------------------------------------OOM控制參數(shù)。
.zonelist = ac->zonelist,
.nodemask = ac->nodemask,
.memcg = NULL,
.gfp_mask = gfp_mask,
.order = order,
};
struct page *page;
*did_some_progress = 0;
/*
* Acquire the oom lock. If that fails, somebody else is
* making progress for us.
*/
if (!mutex_trylock(&oom_lock)) {
*did_some_progress = 1;
schedule_timeout_uninterruptible(1);
return NULL;
}
page = get_page_from_freelist(gfp_mask | __GFP_HARDWALL, order,
ALLOC_WMARK_HIGH|ALLOC_CPUSET, ac);-----------------------------再次使用高水位檢查一次,是否需要啟動(dòng)OOM流程。
if (page)
goto out;
if (!(gfp_mask & __GFP_NOFAIL)) {----------------------------------------------__GFP_NOFAIL是不允許內(nèi)存申請(qǐng)失敗的情況,下面都是允許失敗的處理。
/* Coredumps can quickly deplete all memory reserves */
if (current->flags & PF_DUMPCORE)
goto out;
/* The OOM killer will not help higher order allocs */
if (order > PAGE_ALLOC_COSTLY_ORDER)---------------------------------------order超過(guò)3的申請(qǐng)失敗,不會(huì)啟動(dòng)OOM回收。
goto out;
/* The OOM killer does not needlessly kill tasks for lowmem */
if (ac->high_zoneidx < ZONE_NORMAL)
goto out;
if (pm_suspended_storage())
goto out;
/* The OOM killer may not free memory on a specific node */
if (gfp_mask & __GFP_THISNODE)
goto out;
}
/* Exhausted what can be done so it's blamo time */
if (out_of_memory(&oc) || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL)) {-------------經(jīng)過(guò)上面各種情況,任然需要進(jìn)行OOM處理。調(diào)用out_of_memory()。
*did_some_progress = 1;
if (gfp_mask & __GFP_NOFAIL) {
page = get_page_from_freelist(gfp_mask, order,
ALLOC_NO_WATERMARKS|ALLOC_CPUSET, ac);-------------------------對(duì)于__GFP_NOFAIL的分配情況,降低分配條件從ALLOC_WMARK_HIGH|ALLOC_CPUSET降低到ALLOC_NO_WATERMARKS|ALLOC_CPUSET。
/*
* fallback to ignore cpuset restriction if our nodes
* are depleted
*/
if (!page)
page = get_page_from_freelist(gfp_mask, order,
ALLOC_NO_WATERMARKS, ac);--------------------------------------如果還是分配失敗,再次降低分配標(biāo)準(zhǔn),從ALLOC_NO_WATERMARKS|ALLOC_CPUSET降低到ALLOC_NO_WATERMARKS。真的是為了成功,節(jié)操越來(lái)越低啊。
}
}
out:
mutex_unlock(&oom_lock);
return page;
}
4.3 OOM處理:對(duì)進(jìn)程打分以及殺死最高評(píng)分進(jìn)程
out_of_memory函數(shù)是OOM機(jī)制的核心,他可以分為兩部分。一是調(diào)挑選最’bad‘的進(jìn)程,二是殺死它。
bool out_of_memory(struct oom_control *oc)
{
unsigned long freed = 0;
enum oom_constraint constraint = CONSTRAINT_NONE;
if (oom_killer_disabled)----------------------------------------------------在freeze_processes會(huì)將其置位,即禁止OOM;在thaw_processes會(huì)將其清零,即打開(kāi)OOM。所以,如果在凍結(jié)過(guò)程,不允許OOM。
return false;
if (!is_memcg_oom(oc)) {
blocking_notifier_call_chain(&oom_notify_list, 0, &freed);
if (freed > 0)
/* Got some memory back in the last second. */
return true;
}
if (task_will_free_mem(current)) {----------------------------------------如果當(dāng)前進(jìn)程正因?yàn)楦鞣N原因?qū)⒁顺觯蛘哚尫艃?nèi)存,將當(dāng)前進(jìn)程作為OOM候選者,然后喚醒OOM reaper去收割進(jìn)而釋放內(nèi)存。
mark_oom_victim(current);
wake_oom_reaper(current);
return true;---------------------當(dāng)前進(jìn)程由于自身原因?qū)⒁瞥觯琌OM則將其標(biāo)注為T(mén)IF_MEMDIE狀態(tài);然后喚醒OOM Reaper去處理。不需要經(jīng)過(guò)下面的打分和殺死流程。
}
if (oc->gfp_mask && !(oc->gfp_mask & (__GFP_FS|__GFP_NOFAIL)))-----------如果內(nèi)存申請(qǐng)掩碼包括__GFP_DS或__GFP_NOFAIL,則不進(jìn)行OOM收割。
return true;
constraint = constrained_alloc(oc);--------------------------------------未定義CONFIG_NUMA返回CONSTRAINT_NONE。
if (constraint != CONSTRAINT_MEMORY_POLICY)
oc->nodemask = NULL;
check_panic_on_oom(oc, constraint);--------------------------------------檢查sysctl_panic_on_oom設(shè)置,以及是否由sysrq觸發(fā),來(lái)決定是否觸發(fā)panic。
if (!is_memcg_oom(oc) && sysctl_oom_kill_allocating_task &&--------------如果設(shè)置了sysctl_oom_kill_allocating_task,那么當(dāng)內(nèi)存耗盡時(shí),會(huì)把當(dāng)前申請(qǐng)內(nèi)存分配的進(jìn)程殺掉。
current->mm && !oom_unkillable_task(current, NULL, oc->nodemask) &&
current->signal->oom_score_adj != OOM_SCORE_ADJ_MIN) {
get_task_struct(current);
oc->chosen = current;
oom_kill_process(oc, "Out of memory (oom_kill_allocating_task)");
return true;
}
select_bad_process(oc);-------------------------------------------------遍歷所有進(jìn)程,進(jìn)程下的線程,查找合適的候選進(jìn)程。即得分最高的候選進(jìn)程。
/* Found nothing?!?! Either we hang forever, or we panic. */
if (!oc->chosen && !is_sysrq_oom(oc) && !is_memcg_oom(oc)) {------------如果沒(méi)有合適候選進(jìn)程,并且OOM不是由sysrq觸發(fā)的,進(jìn)入panic。
dump_header(oc, NULL);
panic("Out of memory and no killable processes...\n");
}
if (oc->chosen && oc->chosen != (void *)-1UL) {
oom_kill_process(oc, !is_memcg_oom(oc) ? "Out of memory" :
"Memory cgroup out of memory");----------------------------殺死選中的進(jìn)程。
schedule_timeout_killable(1);
}
return !!oc->chosen;
}
select_bad_process()通過(guò)oom_evaluate_task()來(lái)評(píng)估每個(gè)進(jìn)程的得分,對(duì)于進(jìn)程1、內(nèi)核線程、得分低的進(jìn)程直接跳過(guò)。
static void select_bad_process(struct oom_control *oc)
{
if (is_memcg_oom(oc))
mem_cgroup_scan_tasks(oc->memcg, oom_evaluate_task, oc);
else {
struct task_struct *p;
rcu_read_lock();
for_each_process(p)----------------------------------------------遍歷系統(tǒng)范圍內(nèi)所有進(jìn)程線程。
if (oom_evaluate_task(p, oc))
break;
rcu_read_unlock();
}
oc->chosen_points = oc->chosen_points * 1000 / oc->totalpages;
}
static int oom_evaluate_task(struct task_struct *task, void *arg)
{
struct oom_control *oc = arg;
unsigned long points;
if (oom_unkillable_task(task, NULL, oc->nodemask))-------------------進(jìn)程1以及內(nèi)核線程等等不能被kill的線程跳過(guò)。
goto next;
if (!is_sysrq_oom(oc) && tsk_is_oom_victim(task)) {
if (test_bit(MMF_OOM_SKIP, &task->signal->oom_mm->flags))
goto next;
goto abort;
}
if (oom_task_origin(task)) {
points = ULONG_MAX;
goto select;
}
points = oom_badness(task, NULL, oc->nodemask, oc->totalpages);------對(duì)進(jìn)程task進(jìn)行打分。
if (!points || points < oc->chosen_points)---------------------------這里保證只取最高分的進(jìn)程,所以分?jǐn)?shù)最高者被選中。其他情況則直接跳過(guò)。
goto next;
/* Prefer thread group leaders for display purposes */
if (points == oc->chosen_points && thread_group_leader(oc->chosen))
goto next;
select:
if (oc->chosen)
put_task_struct(oc->chosen);
get_task_struct(task);
oc->chosen = task;--------------------------------------------------更新OOM選中的進(jìn)程和當(dāng)前最高分。
oc->chosen_points = points;
next:
return 0;
abort:
if (oc->chosen)
put_task_struct(oc->chosen);
oc->chosen = (void *)-1UL;
return 1;
}
在oom_badness()中計(jì)算當(dāng)前進(jìn)程的得分,返回選中進(jìn)程的結(jié)構(gòu)體,以及進(jìn)程得分ppoints。
oom_badness()是給進(jìn)程打分的函數(shù),可以說(shuō)是核心中的核心。最終結(jié)果受oom_score_adj和當(dāng)前進(jìn)程內(nèi)存使用量綜合影響。
oom_score_adj為OOM_SCORE_ADJ_MIN的進(jìn)程不參加評(píng)選。進(jìn)程的oom_score_adj值在/proc/xxx/oom_score_adj中。
mm->flags為MMF_OOM_SKIP的進(jìn)程不參加評(píng)選。
處于vfork()中的進(jìn)程不參加評(píng)選。
進(jìn)程的得分取決于其消耗的RSS部分內(nèi)存(文件映射內(nèi)存MM_FILEPAGES、匿名映射內(nèi)存MM_ANONPAGES、shmem內(nèi)存MM_SHMEMPAGES)、匿名交換內(nèi)存MM_SWAPENTS、PTE頁(yè)表所占內(nèi)存、PMD頁(yè)表所占內(nèi)存。
具有root權(quán)限的進(jìn)程只取其97%的得分參加評(píng)選。
所以進(jìn)程得分points=process_pages + oom_score_adj*totalpages/1000;如果是root權(quán)限的進(jìn)程points=process_pages*0.97 + oom_score_adj*totalpages/1000。
在oom_score_adj都為0(默認(rèn)值)的情況下,最終得分跟進(jìn)程自身消耗的內(nèi)存有關(guān);消耗的內(nèi)存越大越容易被Kill。
oom_score_adj每降低1,可以多獲得系統(tǒng)內(nèi)存資源的1/1000使用量。反之,每增加1,則少獲得系統(tǒng)內(nèi)存資源1/1000使用量。
unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
const nodemask_t *nodemask, unsigned long totalpages)
{
long points;
long adj;
if (oom_unkillable_task(p, memcg, nodemask))-------------------------------如果進(jìn)程不可被殺,直接跳過(guò)。
return 0;
p = find_lock_task_mm(p);------------找到進(jìn)程p,并使用task_lock()鎖上。
if (!p)
return 0;
/*
* Do not even consider tasks which are explicitly marked oom
* unkillable or have been already oom reaped or the are in
* the middle of vfork
*/
adj = (long)p->signal->oom_score_adj;--------------------------------------獲取當(dāng)前進(jìn)程的oom_score_adj參數(shù)。
if (adj == OOM_SCORE_ADJ_MIN ||
test_bit(MMF_OOM_SKIP, &p->mm->flags) ||
in_vfork(p)) {
task_unlock(p);
return 0;--------------------------------------------------------------如果當(dāng)前進(jìn)程oom_score_adj為OOM_SCORE_ADJ_MIN的話,就返回0.等于告訴OOM,此進(jìn)程不參數(shù)'bad'評(píng)比。
}
/*
* The baseline for the badness score is the proportion of RAM that each
* task's rss, pagetable and swap space use.
*/
points = get_mm_rss(p->mm) + get_mm_counter(p->mm, MM_SWAPENTS) +
atomic_long_read(&p->mm->nr_ptes) + mm_nr_pmds(p->mm);-----------------可以看出points綜合了內(nèi)存占用情況,包括RSS部分、swap file或者swap device占用內(nèi)存、以及頁(yè)表占用內(nèi)存。
task_unlock(p);
/*
* Root processes get 3% bonus, just like the __vm_enough_memory()
* implementation used by LSMs.
*/
if (has_capability_noaudit(p, CAP_SYS_ADMIN))------------------------------如果是root用戶(hù),增加3%的使用特權(quán)。
points -= (points * 3) / 100;
/* Normalize to oom_score_adj units */
adj *= totalpages / 1000;--------------------------------------------------這里可以看出oom_score_adj對(duì)最終分?jǐn)?shù)的影響,如果oom_score_adj小于0,則最終points就會(huì)變小,進(jìn)程更加不會(huì)被選中。
points += adj;-------------------------------------------------------------將歸一化后的adj和points求和,作為當(dāng)前進(jìn)程的分?jǐn)?shù)。
/*
* Never return 0 for an eligible task regardless of the root bonus and
* oom_score_adj (oom_score_adj can't be OOM_SCORE_ADJ_MIN here).
*/
return points > 0 ? points : 1;
}
https://www.cnblogs.com/arnoldlu/p/8567559.html#oom_badness
相關(guān)評(píng)說(shuō):
太和區(qū)基礎(chǔ): ______ Linux設(shè)置內(nèi)核參數(shù)的方法1 內(nèi)核參數(shù)的查看方法 使用“sysctl -a”命令可以查看所有正在使用的內(nèi)核參數(shù).內(nèi)核參數(shù)比較多(一般多達(dá)500項(xiàng)),按照前綴主要分為以下幾大類(lèi):net.ipv4、net.ipv6、net.core、vm、fs、dev.parport、dev.cdrom 、...
太和區(qū)基礎(chǔ): ______ AOE - Area Effect Damage,區(qū)域作用魔法.指的是一個(gè)可以傷害一個(gè)區(qū)域中的一群怪物的魔法,就像魔獸爭(zhēng)霸三中的暴風(fēng)雪魔法. AE - Area Effect,區(qū)域作用傷害 AFK - Away from Keyboard,離開(kāi)鍵盤(pán).這意味著玩家離開(kāi)了他的電腦. ...
太和區(qū)基礎(chǔ): ______ There are situations under which the kernel will send SIGKILL to a process. Others have mentioned the Linux OOM killer; a more rarely seen one is if you have a CPU-time resource hard limit set (such as via the ulimit shell-builtin) then the kernel will ...
太和區(qū)基礎(chǔ): ______ zabbix proxy的特點(diǎn)決定了中心的server、數(shù)據(jù)庫(kù)是一個(gè)中心的瓶頸,尤其是數(shù)據(jù)庫(kù).至于數(shù)據(jù)大量回傳的問(wèn)題,在server宕機(jī)的時(shí)候確定會(huì)很?chē)?yán)重.解決方法:1.優(yōu)化配置,減少Proxy保留的數(shù)據(jù)時(shí)間,這樣回傳數(shù)據(jù)回減少很多2.server down的問(wèn)題,重點(diǎn)查下原因,莫名其妙的down的問(wèn)題看下是否是因?yàn)閮?nèi)存不足觸發(fā)的oom killer;如果的是的話,加大swap分區(qū)或者加內(nèi)容吧3.數(shù)據(jù)庫(kù)優(yōu)化,這方面沒(méi)辦法具體說(shuō),找dba幫忙吧;4.數(shù)據(jù)庫(kù)上ssd,這樣寫(xiě)性能會(huì)有很大提升 注意:,量的時(shí)候,server、proxy、數(shù)據(jù)庫(kù)、前端頁(yè)面最好都是找一個(gè)設(shè)備專(zhuān)門(mén)去跑,尤其是數(shù)據(jù)庫(kù)建議找一個(gè)高配置的設(shè)備.
太和區(qū)基礎(chǔ): ______ 完成對(duì)oracle-validated的安裝后操作系統(tǒng)軟件包環(huán)境也就水道渠成了,此外該oracle-validated包還會(huì)幫助我們?cè)O(shè)置必要的Linux內(nèi)核參數(shù),具體來(lái)說(shuō)它會(huì)修改/etc/sysctl.conf配置文件中的參數(shù)到Oracle推薦的值,以下為完成oracle-validated安裝后...
太和區(qū)基礎(chǔ): ______ 一、Android為什么會(huì)選擇Linux 這就與Linux的一些特性有關(guān)了 1、強(qiáng)大的內(nèi)存管理和進(jìn)程管理方案 2、基于權(quán)限的安全模式 3、支持共享庫(kù) 4、經(jīng)過(guò)認(rèn)證的驅(qū)動(dòng)模型 5、Linux本身就是開(kāi)源項(xiàng)目 更多關(guān)于上述特性的信息可以參考Linux 2.6版內(nèi)...
太和區(qū)基礎(chǔ): ______ Android是一個(gè)專(zhuān)門(mén)針對(duì)移動(dòng)設(shè)備的軟件集,包括一個(gè)操作系統(tǒng),中間件和一些重要的應(yīng)用程序.Android SDK 提供了在Android平臺(tái)使用java語(yǔ)言進(jìn)行android 應(yīng)用程序開(kāi)發(fā)必須的工具和API接口.Android 系統(tǒng)架構(gòu)除了Linux2.6內(nèi)核之外,還提...
太和區(qū)基礎(chǔ): ______ AC - Armor Class,盔甲級(jí)別或防御. Add - 一只額外的怪物加入到現(xiàn)有的戰(zhàn)斗中. AOE - Area Effect Damage,區(qū)域作用魔法.指的是一個(gè)可以傷害一個(gè)區(qū)域中的一群怪物的魔法,就像魔獸爭(zhēng)霸三中的暴風(fēng)雪魔法. AE - Area Effect,區(qū)域作用...
太和區(qū)基礎(chǔ): ______ 要讓android應(yīng)用不被殺死,可以開(kāi)啟一個(gè)service,一直檢測(cè)是否關(guān)閉了應(yīng)用,一旦關(guān)閉馬上重新啟動(dòng). 當(dāng)然首先要保證service不被殺死,應(yīng)當(dāng)提升service的優(yōu)先級(jí),設(shè)為前臺(tái)運(yùn)行.也可以開(kāi)啟兩個(gè)service互相檢測(cè),一旦其中一個(gè)被關(guān)閉,另一個(gè) 馬上重啟對(duì)方.可以保證其生命穩(wěn)定.這種方法也不是都行的,有些系統(tǒng)仍然能殺死.
太和區(qū)基礎(chǔ): ______ 女孩qq英文網(wǎng)名 ABIGALE 原為古希伯來(lái)名,意思是"最初的歡樂(lè)"或"歡樂(lè)之本".在圣經(jīng)撒母爾記上篇第二十五章中,講到了一位早期名叫Abigale的人的故事.在這個(gè)故事之中,她是一位聰明、美麗的女人.她有過(guò)人的智能和謀略.因而...
五谷類(lèi)是復(fù)合碳水化合物和膳食纖維的重要來(lái)源。增加五谷類(lèi)的攝入是一種改善營(yíng)養(yǎng)狀況的簡(jiǎn)單方法,燕麥、糙米、小米、大麥等食物是你最好的選擇。你可以選擇不含糖分或添加劑的全麥面包,也可以選擇無(wú)糖的牛奶什錦早餐。浸泡牛奶什錦早餐10分鐘至12小時(shí),可以去除磷酸。因?yàn)榱姿釙?huì)影響食物中礦物質(zhì)的吸收。
蔬菜
蔬菜可以為我們提供維生素、膳食纖維、礦物質(zhì)、抗氧化劑和植物性化學(xué)活性物質(zhì)。蔬菜可以保護(hù)機(jī)體免患疾病,提高機(jī)體的修復(fù)能力。孕期攝入富含維生素A的蔬菜是非常必要的。蔬菜中的維生素A和動(dòng)物類(lèi)食品中的維生素A存在形式不同,動(dòng)物食品中的維生素A以視黃醇的形式存在,因此有攝入過(guò)量的風(fēng)險(xiǎn),而蔬菜不存在攝入過(guò)量的風(fēng)險(xiǎn)。
盡量生吃蔬菜,或者在保證營(yíng)養(yǎng)價(jià)值不被破壞的情況下進(jìn)行烹調(diào)。烹調(diào)蔬菜一定要注意,過(guò)度的烹調(diào)會(huì)損失大量的維生素和礦物質(zhì),最好采取蒸煮或者少量油旺火炒的烹調(diào)方式,這種方式不會(huì)發(fā)生維生素和礦物質(zhì)的丟失。蔬菜的種類(lèi)有很多,各種蔬菜含有的礦物質(zhì)種類(lèi)和含量各不相同。一些不常見(jiàn)的蔬菜,如海藻,就富含鐵和其他礦物質(zhì)。
有機(jī)蔬菜由于沒(méi)有農(nóng)藥殘留,可以更放心地食用。由于種植有機(jī)食品的土壤含有很豐富的礦物質(zhì),因此對(duì)人體更有益。蔬菜表皮的營(yíng)養(yǎng)價(jià)值比較高而且沒(méi)有農(nóng)藥殘留,因此可以放心食用。
豆制品——黃豆、小扁豆、豌豆
豆制品是維生素、礦物質(zhì)和蛋白質(zhì)的良好來(lái)源,黃豆含有所有的必需氨基酸。
可以做湯吃,燜著吃或者做咖喱和面條吃。
豆子發(fā)芽以后,更容易消化,并且含有更多的礦物質(zhì)。豆芽在冰箱放置幾天以后,味道更加鮮美、爽脆。豆芽可以煮著吃、拌沙拉或者夾到三明治里吃。
水果可以為機(jī)體提供維生素(特別是維生素C)、纖維素和礦物質(zhì)。
一個(gè)完整的水果(包括皮和核)提供的能量,比制成果汁以后提供的能量持續(xù)時(shí)間要長(zhǎng)1~2個(gè)小時(shí)。
如果感覺(jué)水果攝入不足,可以把水果融入一日三餐,作為正餐的一部分:比如,可以把梨加入早餐的燕麥粥中,在酸奶中添加草莓,往沙拉中加入蘋(píng)果或者菠蘿。
肉類(lèi)
肉類(lèi)含有豐富的蛋白質(zhì)、維生素和礦物質(zhì),同時(shí)也含有較多的飽和脂肪,因此適量攝入肉制品,應(yīng)該控制在每日食物攝入的10%以?xún)?nèi)。
家禽的脂肪含量低于紅肉的脂肪含量。紅肉中的脂肪通常是飽和脂肪,這種脂肪對(duì)人的心臟有害。
魚(yú)肉類(lèi)
魚(yú)肉類(lèi)食品含有豐富的維生素,礦物質(zhì),蛋白質(zhì)和必需脂肪酸,該系列的必需脂肪酸是向孕婦推薦的,是胎兒發(fā)育必不可少的。
紅魚(yú)類(lèi)如沙丁魚(yú)、鯖魚(yú)、金槍魚(yú)、鯡魚(yú)、鮭魚(yú)、青魚(yú)等,是必需脂肪酸和維生素D的良好來(lái)源,每周至少吃3次魚(yú)。
白魚(yú)類(lèi),如草魚(yú)、鰱魚(yú)、鱈魚(yú)是維生素B12和蛋白質(zhì)的良好來(lái)源。
烤魚(yú)或者熏魚(yú)時(shí)只需要少量的油。如果用油炸,魚(yú)的營(yíng)養(yǎng)價(jià)值會(huì)損失較多。
魚(yú)罐頭雖然也含有礦物質(zhì)和維生素,但是在加工過(guò)程中損失了大部分ω-3不飽和脂肪酸,而不飽和必需脂肪酸是孕期必不可少的,因此魚(yú)罐頭不如新鮮魚(yú)營(yíng)養(yǎng)價(jià)值高。