0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

缺页异常是匿名映射缺页异常分析

Linux阅码场 来源:韩传华 作者:韩传华 2020-09-09 10:55 次阅读

前面讲到过写时复制缺页异常(COW),一般用于父子进程之间共享页,而我们会常见一种缺页异常是匿名映射缺页异常,今天我们就来讨论下这种缺页异常,让大家彻底理解它。注:本文使用linux-5.0内核源代码。文章分为以下几节内容:

1.匿名映射缺页异常的触发情况2.0页是什么?为什么使用0页?

3.源代码分析

3.1 触发条件

3.2 第一次读匿名页

3.3 第一次写匿名页

3.4 读之后写匿名页

4.应用层实验

5.总结

在讲解匿名映射缺页异常之前我们先要了解以下什么是匿名页?与匿名页相对应的是文件页,文件页我们应该很好理解,就是映射文件的页,如:通过mmap映射文件到虚拟内存然后读文件数据,进程的代码数据段等,这些页有后备缓存也就是块设备上的文件,而匿名页就是没有关联到文件的页,如:进程的堆、栈等。还有一点需要注意:下面讨论的都是私有的匿名页的情况,共享匿名页在内核演变为文件映射缺页异常(伪文件系统),后面有机会我们会讲解,感兴趣的小伙伴可以看一看mmap的代码实现对共享匿名页的处理。

一,匿名映射缺页异常的触发情况

前面我们讲解了什么是匿名页,那么思考一下什么情况下会触发匿名映射缺页异常呢?这种异常对于我们来说非常常见:

1.当我们应用程序使用malloc来申请一块内存(堆分配),在没有使用这块内存之前,仅仅是分配了虚拟内存,并没有分配物理内存,第一次去访问的时候才会通过触发缺页异常来分配物理页建立和虚拟页的映射关系。

2.当我们应用程序使用mmap来创建匿名的内存映射的时候,页同样只是分配了虚拟内存,并没有分配物理内存,第一次去访问的时候才会通过触发缺页异常来分配物理页建立和虚拟页的映射关系。

3.当函数的局部变量比较大,或者是函数调用的层次比较深,导致了当前的栈不够用了,这个时候需要扩大栈。当然了上面的这几种场景对应应用程序来说是透明的,内核为用户程序做了大量的处理工作,下面几节会看到如何处理。

二,0页是什么?为什么使用0页?

这里为什么会说到0页呢?什么是0页呢?是地址为0的页吗?答案是:系统初始化过程中分配了一页的内存,这段内存全部被填充0。下面我们来看下0页如何分配的:在arch/arm64/mm/mmu.c中:

61/* 62 * Empty_zero_page is a special page that is used for zero-initialized data 63 * and COW. 64 */ 65 unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss; 66 EXPORT_SYMBOL(empty_zero_page);

可以看到定义了一个全局变量,大小为一页,页对齐到bss段,所有这段数据内核初始化的时候会被清零,所有称之为0页。

那么为什么使用0页呢?一个是它的数据都是被0填充,读的时候数据都是0,二是节约内存,匿名页面第一次读的时候数据都是0都会映射到这页中从而节约内存(共享0页),那么如果有进程要去写这个这个页会怎样呢?答案是发生COW重新分配页来写。

三,源代码分析

3.1 触发条件

当第一节中的触发情况发生的时候,处理器就会发生缺页异常,从处理器架构相关部分过渡到处理器无关部分,最终到达handle_pte_fault函数:

3742 static vm_fault_t handle_pte_fault(struct vm_fault *vmf) 3743 { 3744 pte_t entry; ... 3782 if (!vmf->pte) { 3783 if (vma_is_anonymous(vmf->vma)) 3784 return do_anonymous_page(vmf); 3785 else 3786 return do_fault(vmf); 3787 }

3782和3783行是匿名映射缺页异常的触发条件:

1.发生缺页的地址所在页表项不存在。

2.是匿名页发生的,即是vma->vm_ops为空。

当满足这两个条件的时候就会调用do_anonymous_page函数来处理匿名映射缺页异常。

2871 /* 2872 * We enter with non-exclusive mmap_sem (to exclude vma changes, 2873 * but allow concurrent faults), and pte mapped but not yet locked. 2874 * We return with mmap_sem still held, but pte unmapped and unlocked. 2875 */ 2876 static vm_fault_t do_anonymous_page(struct vm_fault *vmf) 2877 { 2878 struct vm_area_struct *vma = vmf->vma; 2879 struct mem_cgroup *memcg; 2880 struct page *page; 2881 vm_fault_t ret = 0; 2882 pte_t entry; 2883 2884 /* File mapping without ->vm_ops ? */ 2885 if (vma->vm_flags & VM_SHARED) 2886 return VM_FAULT_SIGBUS; 2887 2888/* 2889 ¦* Use pte_alloc() instead of pte_alloc_map(). We can't run 2890 ¦* pte_offset_map() on pmds where a huge pmd might be created 2891 ¦* from a different thread. 2892 ¦* 2893 ¦* pte_alloc_map() is safe to use under down_write(mmap_sem) or when 2894 ¦* parallel threads are excluded by other means. 2895 ¦* 2896 ¦* Here we only have down_read(mmap_sem). 2897 ¦*/ 2898 if (pte_alloc(vma->vm_mm, vmf->pmd)) 2899 return VM_FAULT_OOM; 2904 ...

2885行判断:发生缺页的vma是否为私有映射,这个函数处理的是私有的匿名映射。

2898行如何页表不存在则分配页表(有可能缺页地址的页表项所在的直接页表不存在)。

3.2 第一次读匿名页情况

... 2905 /* Use the zero-page for reads */ 2906 if (!(vmf->flags & FAULT_FLAG_WRITE) && 2907 !mm_forbids_zeropage(vma->vm_mm)) { 2908 entry = pte_mkspecial(pfn_pte(my_zero_pfn(vmf->address), 2909 vma->vm_page_prot)); 2910 vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd, 2911 vmf->address, &vmf->ptl); 2912 if (!pte_none(*vmf->pte)) 2913 goto unlock; 2914 ret = check_stable_address_space(vma->vm_mm); 2915 if (ret) 2916 goto unlock; 2917 /* Deliver the page fault to userland, check inside PT lock */ 2918 if (userfaultfd_missing(vma)) { 2919 pte_unmap_unlock(vmf->pte, vmf->ptl); 2920 return handle_userfault(vmf, VM_UFFD_MISSING); 2921 } 2922 goto setpte; 2923 } ... 2968 setpte: 2969 set_pte_at(vma->vm_mm, vmf->address, vmf->pte, entry);

‍2906到2923行是处理的是私有匿名页读的情况:这里就会用到我们上面将的0页了。

2906和 2907行判断是否是由于读操作导致的缺页而且没有禁止0页。

2908-2909行是核心部分:设置页表项的值映射到0页。

我们主要研究这个语句:pfn_pte用来将页帧号和页表属性拼接为页表项值:

arch/arm64/include/asm/pgtable.h:77 #define pfn_pte(pfn,prot) 78 __pte(__phys_to_pte_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))

是将pfn左移PAGE_SHIFT位(一般为12bit),或上pgprot_val(prot)

先看my_zero_pfn:

include/asm-generic/pgtable.h:875staticinlineunsignedlongmy_zero_pfn(unsignedlongaddr) 876 { 877 extern unsigned long zero_pfn; 878 return zero_pfn; 879 }

||/

mm/memory.c: 126 unsigned long zero_pfn __read_mostly; 127 EXPORT_SYMBOL(zero_pfn); 128 129 unsigned long highest_memmap_pfn __read_mostly; 130 131 /* 132 * CONFIG_MMU architectures set up ZERO_PAGE in their paging_init() 133 */ 134 static int __init init_zero_pfn(void) 135 { 136 zero_pfn = page_to_pfn(ZERO_PAGE(0)); 137 return 0; 138 } 139 core_initcall(init_zero_pfn);

||/

arch/arm64/include/asm/pgtable.h:54/* 55 * ZERO_PAGE is a global shared page that is always zero: used 56 * for zero-mapped memory areas etc.. 57 */ 58 extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; 59 #define ZERO_PAGE(vaddr) phys_to_page(__pa_symbol(empty_zero_page))

最终我们看到使用的就是内核初始化设置的empty_zero_page这个0页得到页帧号。再看看pfn_pte的第二个参数vma->vm_pageprot,这是vma的访问权限,在做内存映射mmap的时候会被设置。

那么我们想知道的时候是什么时候0页被设置为了只读属性的(也就是页表项何时被设置为只读)?

我们带着这个问题去在内核代码中寻找答案。其实代码看到这里一般看不到头绪,但是我们要知道何时vma的vm_page_prot成员被设置的,如何被设置的,有可能就能找到答案。

我们到mm/mmap.c中去寻找答案:我们以do_brk_flags函数为例,这是设置堆的函数我们关注到3040行设置了vm_page_prot:

3040vma->vm_page_prot=vm_get_page_prot(flags);

||/

110 pgprot_t vm_get_page_prot(unsigned long vm_flags) 111 { 112 pgprot_t ret = __pgprot(pgprot_val(protection_map[vm_flags & 113 (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]) | 114 pgprot_val(arch_vm_get_page_prot(vm_flags))); 115 116 return arch_filter_pgprot(ret); 117 } 118 EXPORT_SYMBOL(vm_get_page_prot);

vm_get_page_prot函数会根据传递来的vmflags是否为VMREAD|VMWRITE|VMEXEC|VMSHARED来转换为保护位组合,继续往下看||/

78 /* description of effects of mapping type and prot in current implementation. 79 * this is due to the limited x86 page protection hardware. The expected 80 * behavior is in parens: 81 * 82 * map_type prot 83 * PROT_NONE PROT_READ PROT_WRITE PROT_EXEC 84 * MAP_SHARED r: (no) no r: (yes) yes r: (no) yes r: (no) yes 85 * w: (no) no w: (no) no w: (yes) yes w: (no) no 86 * x: (no) no x: (no) yes x: (no) yes x: (yes) yes 87 * 88 * MAP_PRIVATE r: (no) no r: (yes) yes r: (no) yes r: (no) yes 89 * w: (no) no w: (no) no w: (copy) copy w: (no) no 90 * x: (no) no x: (no) yes x: (no) yes x: (yes) yes 91 * 92 * On arm64, PROT_EXEC has the following behaviour for both MAP_SHARED and 93 * MAP_PRIVATE: 94 * r: (no) no 95 * w: (no) no 96 * x: (yes) yes 97 */ 98 pgprot_t protection_map[16] __ro_after_init = { 99 __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, 100 __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 101 };

protection_map数组定义了从P000到S111一共16种组合,P表示私有(Private),S表示共享(Share),后面三个数字依次为可读、可写、可执行,如:_S010表示共享、不可读、可写、不可执行。

||/

arch/arm64/include/asm/pgtable-prot.h: 93 #define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN) 94 #define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) 95 #define PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE) 96 #define PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN) 97 #define PAGE_READONLY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN) 98 #define PAGE_EXECONLY __pgprot(_PAGE_DEFAULT | PTE_RDONLY | PTE_NG | PTE_PXN) 99 100 #define __P000 PAGE_NONE 101 #define __P001 PAGE_READONLY 102 #define __P010 PAGE_READONLY 103 #define __P011 PAGE_READONLY 104 #define __P100 PAGE_EXECONLY 105 #define __P101 PAGE_READONLY_EXEC 106 #define __P110 PAGE_READONLY_EXEC 107 #define __P111 PAGE_READONLY_EXEC 108 109 #define __S000 PAGE_NONE 110 #define __S001 PAGE_READONLY 111 #define __S010 PAGE_SHARED 112 #define __S011 PAGE_SHARED 113 #define __S100 PAGE_EXECONLY 114 #define __S101 PAGE_READONLY_EXEC 115 #define __S110 PAGE_SHARED_EXEC 116 #define __S111 PAGE_SHARED_EXEC

可以发现对于私有的映射只有只读(PTE_RDONLY)没有可写属性(PTE_WRITE)105-107行,虽然之前设置的时候是设置了可写(VM_WRITE)!而对应共享映射则会有可写属性。

而这个被设置的保护位组合最终会在缺页异常中被设置到页表中:上面说到的do_anonymous_page函数:

2908 entry = pte_mkspecial(pfn_pte(my_zero_pfn(vmf->address),2909vma->vm_page_prot));

对于私有匿名映射的页,假设设置的vmflags为VMREAD|VMWRITE则对应的保护位组合为:P110即为PAGE_READONLY_EXEC=pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PT_ENG | PTE_PXN)不会设置为可写。

所以就将其页表设置为了只读!!!

2922行跳转到setpte去将设置好的页表项值填写到页表项中。

当匿名页读之后再次去写时候会由于页表属性为只读导致COW缺页异常,详将COW相关文章,再此不在赘述。下面用图说话:

3.3 第一次写匿名页的情况

接着do_anonymous_page函数继续往下分析:

2876 static vm_fault_t do_anonymous_page(struct vm_fault *vmf) 2877 { ... 2924 2925 /* Allocate our own private page. */ 2926 if (unlikely(anon_vma_prepare(vma))) 2927 goto oom; 2928 page = alloc_zeroed_user_highpage_movable(vma, vmf->address); 2929 if (!page) 2930 goto oom; 2931 2932 if (mem_cgroup_try_charge_delay(page, vma->vm_mm, GFP_KERNEL, &memcg, 2933 false)) 2934 goto oom_free_page; 2935 2936 /* 2937 ¦* The memory barrier inside __SetPageUptodate makes sure that 2938 ¦* preceeding stores to the page contents become visible before 2939 ¦* the set_pte_at() write. 2940 ¦*/ 2941 __SetPageUptodate(page); 2942 2943 entry = mk_pte(page, vma->vm_page_prot); 2944 if (vma->vm_flags & VM_WRITE) 2945 entry = pte_mkwrite(pte_mkdirty(entry));2946 2947 vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd, vmf->address, 2948 &vmf->ptl); 2949 if (!pte_none(*vmf->pte)) 2950 goto release; 2951 2952 ret = check_stable_address_space(vma->vm_mm); 2953 if (ret) 2954 goto release; 2955 2956 /* Deliver the page fault to userland, check inside PT lock */ 2957 if (userfaultfd_missing(vma)) { 2958 pte_unmap_unlock(vmf->pte, vmf->ptl); 2959 mem_cgroup_cancel_charge(page, memcg, false); 2960 put_page(page); 2961 return handle_userfault(vmf, VM_UFFD_MISSING); 2962 } 2963 2964 inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES); 2965 page_add_new_anon_rmap(page, vma, vmf->address, false); 2966 mem_cgroup_commit_charge(page, memcg, false, false); 2967 lru_cache_add_active_or_unevictable(page, vma);2968setpte:2969set_pte_at(vma->vm_mm,vmf->address,vmf->pte,entry); 2970 2971 /* No need to invalidate - it was non-present before */ 2972 update_mmu_cache(vma, vmf->address, vmf->pte); 2973 unlock: 2974 pte_unmap_unlock(vmf->pte, vmf->ptl); 2975 return ret; 2976 release: 2977 mem_cgroup_cancel_charge(page, memcg, false); 2978 put_page(page); 2979 goto unlock; 2980 oom_free_page: 2981 put_page(page); 2982 oom: 2983 return VM_FAULT_OOM; 2984 }

当判断不是读操作导致的缺页的时候,则是写操作造成,处理写私有的匿名页情况,请记住这依然是第一次访问这个匿名页只不过是写访问而已。

2928行会分配一个高端可迁移的被0填充的物理页。2941设置页中数据有效2943使用页帧号和vma的访问权限设置页表项值(注意:这个时候页表项属性依然为只读)。

2944-2945行如果vma可写,则设置页表项值为脏且*可写*(这个时候才设置为可写)。

2964行匿名页计数统计2965行添加到匿名页的反向映射中2967行添加到lru链表2969将设置好的页表项值填充到页表项中。

下面用图说话:

3.4 读之后写匿名页

读之后写匿名页,其实已经很简单了,那就是发生COW写时复制缺页。下面依然看图说话:

四,应用层实验

实验1:主要体验下内核的按需分配页策略!实验代码:mmap映射10 * 4096 * 4096/1M=160M内存空间,映射和写页前后获得内存使用情况:

1 #include 2 #include 3 #include 4 #include 5 6 7 #define MAP_LEN (10 * 4096 * 4096) 8 9 int main(int argc, char **argv) 10 { 11 char *p; 12 int i; 13 14 15 puts("before mmap ->please exec: free -m "); 16 sleep(10); 17 p = (char *)mmap(0, MAP_LEN, PROT_READ |PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 18 19 puts("after mmap ->please exec: free -m "); 20 puts("before write.... "); 21 sleep(10); 22 23 for(i=0;i <4096 *10; i++) 24 p[4096 * i] = 0x55; 25 26 27 puts("after write ->please exec: free -m "); 28 29 pause(); 30 31 return 0;32}

执行结果:

出现“before mmap ->please exec: free -m”打印后执行:

$ free -m 总计 已用 空闲 共享 缓冲/缓存 可用内存:15921 6561 462 796 8897 8214交换:16290 702 15588

出现“after mmap ->please exec: free -m”打印后执行:

$ free -m 总计 已用 空闲 共享 缓冲/缓存 可用内存:15921 6565 483 771 8872 8236交换:16290 702 15588

出现“after write ->please exec: free -m”后执行:

$:~/study/user_test/page-fault$ free -m 总计 已用 空闲 共享 缓冲/缓存 可用内存:15921 6727 322 770 8871 8076交换:16290 702 15588

我们只关注已用内存,可以发现映射前后基本上已用内存没有变化(考虑到其他内存申请情况存在,也会有内存变化)是6561M和6565M,说明mmap的时候并没有分配物理内存,写之后发现内存使用为6727M, 6727-6565=162M与我们mmap的大小基本一致,说明了匿名页实际写的时候才会分配等量的物理内存。

实验2:主要体验下匿名页读之后写内存页申请情况实验代码:mmap映射10 * 4096 * 4096/1M=160M内存空间,映射、读然后写页前后获得内存使用情况:

1 #include 2 #include 3 #include 4 #include 5 6 7 #define MAP_LEN (10 * 4096 * 4096) 8 9 int main(int argc, char **argv) 10 { 11 char *p; 12 int i; 13 14 15 puts("before mmap...pls show free:. "); 16 sleep(10);✗ 17 p = (char *)mmap(0, MAP_LEN, PROT_READ |PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 18 19 puts("after mmap.... "); 20 21 puts("before read...pls show free:. "); 22 sleep(10); 23 24 puts("start read.... "); 25 26 27 for(i=0;i <4096 *10; i++) 28 printf("%d ", p[4096 * i]); 29 printf(" "); 30 31 puts("after read....pls show free: "); 32 33 sleep(10); 34 35 puts("start write.... "); 36 37 for(i=0;i <4096 *10; i++) 38 p[4096 * i] = 0x55; 39 40 41 puts("after write...pls show free:. "); 42 43 pause(); 44 45 return 0; 46 }

执行结果:出现"before mmap ->please exec: free -m" 后执行:

$ free -m 总计 已用 空闲 共享 缓冲/缓存 可用内存:15921 6590 631 780 8700 8164交换:16290 702 15588

出现"before read ->please exec: free -m"后执行:

$ free -m 总计 已用 空闲 共享 缓冲/缓存 可用内存:15921 6586 644 770 8690 8178交换:16290 702 15588

出现"after read ->please exec: free -m"后执行:

$ free -m 总计 已用 空闲 共享 缓冲/缓存 可用内存:15921 6587 624 789 8709 8158交换:16290 702 15588

出现"after write ->please exec: free -m"后执行:

$ free -m 总计 已用 空闲 共享 缓冲/缓存 可用内存:15921 6749 462 789 8709 7996交换:16290 702 15588

可以发现:读之后和之前基本上内存使用没有变化(实际上映射到了0页,这是内核初始化时候分配好的),知道写之后6749-6587=162M符合预期,而且打印可以发现数据全为0。

分析:实际上,mmap的时候只是申请了一块vma,读的时候发生一次缺页异常,映射到0页,所有内存没有分配,当再次写这个页面的时候,发生了COW分配新页(cow中分配新页的时候会判断原来的页是否为0页,如果为0页就直接分配页然后用0填充)。

五,总结

匿名映射缺页异常是我们遇到的一种很常用的一种异常,对于匿名映射,映射完成之后,只是获得了一块虚拟内存,并没有分配物理内存,当第一次访问的时候:如果是读访问,会将虚拟页映射到0页,以减少不必要的内存分配;如果是写访问,则会分配新的物理页,并用0填充,然后映射到虚拟页上去。而如果是先读访问一页然后写访问这一页,则会发生两次缺页异常:第一次是匿名页缺页异常的读的处理,第二次是写时复制缺页异常处理。

原文标题:Linux内核虚拟内存管理之匿名映射缺页异常分析

文章出处:【微信公众号:Linuxer】欢迎添加关注!文章转载请注明出处。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11304

    浏览量

    209493
  • COW
    COW
    +关注

    关注

    0

    文章

    4

    浏览量

    8014
  • 虚拟内存
    +关注

    关注

    0

    文章

    77

    浏览量

    8059

原文标题:Linux内核虚拟内存管理之匿名映射缺页异常分析

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    串口通讯异常处理方法 串口设备连接方式

    串口通信异常处理方法 1. 异常检测 在串口通信中,首先需要能够检测到异常情况。异常检测可以通过以下几种方式实现: 硬件检测 :利用串口硬件的中断和状态寄存器来检测
    的头像 发表于 12-27 09:53 75次阅读

    柔性测斜仪数据异常故障分析及解决方法

    、不准确等,这些问题严重影响了测量的准确性和可靠性。本文将针对柔性测斜仪数据异常故障进行深入分析,并提出相应的解决方法,以帮助用户更好地使用和维护柔性测斜仪。测量
    的头像 发表于 11-20 14:37 151次阅读
    柔性测斜仪数据<b class='flag-5'>异常</b>故障<b class='flag-5'>分析</b>及解决方法

    TAS5613报告端口异常是什么原因?

    高手些,我的5613报告端口异常,不知道原因 SD : 为低 CLIP : 为高 READY : 为低 请问是什么原因?
    发表于 11-05 06:57

    单片机异常复位的原因

    单片机异常复位是指单片机在正常工作过程中,非预期地返回到初始状态或重启。这种异常复位现象可能由多种因素引起,以下是对单片机异常复位原因的详细分析
    的头像 发表于 10-17 17:56 920次阅读

    仪表温度异常的产生原因

    电子发烧友网站提供《仪表温度异常的产生原因.docx》资料免费下载
    发表于 09-12 14:09 0次下载

    谷景揭秘电感发热异常是电感量小的原因吗

    电感在电子电路中扮演者非常重要的角色,但是电感在使用中有时候可能会出现发热异常的问题。引起电感发热异常的原因是有很多种的,包括电感量的大小、线圈的电阻、电流的大小、磁芯材料等。 有人说电感发热异常是
    的头像 发表于 08-27 14:52 292次阅读

    TI电量计通讯异常分析经验

    电子发烧友网站提供《TI电量计通讯异常分析经验.pdf》资料免费下载
    发表于 08-23 10:12 0次下载
    TI电量计通讯<b class='flag-5'>异常</b>的<b class='flag-5'>分析</b>经验

    LMH7322 LVDS输出异常是什么原因导致的?

    LMH7322 LVDS输出异常
    发表于 08-08 08:30

    pFC电感电流异常如何解决

    电流异常是一个常见问题,可能导致设备性能下降、效率降低甚至损坏。本文将介绍PFC电感电流异常的原因及其解决方法。 二、PFC电感电流异常的原因 1. 电感元件本身的特性 PFC电路中的电感元件一般采用铁芯或空心线圈制成,其磁场与
    的头像 发表于 07-16 14:44 1058次阅读

    差分探头测量电压尖峰异常问题的分析与解决

    确的测量结果。本文将分析差分探头测量电压尖峰异常的原因,并提出可能的解决方案。 问题描述: 在使用差分探头进行电压测量时,可能会观察到电压尖峰的幅值异常或形状异常。这种
    的头像 发表于 06-13 09:35 530次阅读
    差分探头测量电压尖峰<b class='flag-5'>异常</b>问题的<b class='flag-5'>分析</b>与解决

    PLC出现问题时如何快速判断是CPU异常

    CPU异常是较为常见且影响较大的问题之一。本文将从多个方面探讨如何快速判断PLC出现问题时是否为CPU异常,并提供相应的解决方法和建议。
    的头像 发表于 06-12 11:13 859次阅读

    双线磁环共模电感测试中出现异常的原因分析

    电子发烧友网站提供《双线磁环共模电感测试中出现异常的原因分析.docx》资料免费下载
    发表于 06-03 14:50 0次下载

    STM32H7B0通过QSPI地址映射外部flash开始使用正常,出现QSPI功能异常是什么原因导致的?

    STM32H7B0 通过QSPI地址映射外部flash开始使用正常,后面出现QSPI功能异常(直接寻址和地址映射均不能访问外部flash),QSPI IO2作为QSPI功能使用始终为低电平,但作为
    发表于 03-08 06:34

    晶振输出频率异常怎么办?

    晶振输出频率异常怎么办? 晶振输出频率异常是指晶振输出信号的频率与预期不符。晶振作为一种常见的时钟源,广泛应用于各种电子设备中,包括计算机、手机、通信设备等。因此,当晶振输出频率异常时,会导致设备
    的头像 发表于 01-24 16:11 917次阅读

    如何解决C语言中的“访问权限冲突”异常?C语言引发异常原因分析

    如何解决C语言中的“访问权限冲突”异常?C语言引发异常原因分析  在C语言中,访问权限冲突异常常是由于尝试访问未授权的变量、函数或其他数据
    的头像 发表于 01-12 16:03 5710次阅读