@@ -777,11 +777,94 @@ Thread.UncaughtExceptionHandler捕获到OutOfMemoryError时记录/proc/pid目录
777
777
## 什么情况下虚拟内存地址空间才会耗尽
778
778
779
779
780
- 说面分析了那么多,结论就是因为虚拟内存空间耗尽导致的,但是究竟什么情况才会出现耗尽的情况?
780
+ 说面分析了那么多,结论就是因为虚拟内存空间耗尽导致的,但是究竟什么情况才会出现耗尽的情况?
781
+
782
+ 内存是程序运行时的存储地址空间,可分为虚拟地址空间和物理地址空间。虚拟地址空间是相对进程而言的,每个进程都有独立的地址空间(如32位程序都有4GB的虚拟地址空间)。物理地址空间就是由硬件(内存条)提供的存储空间,物理地址空间被所有进程共享。
783
+
784
+ Linux采用虚拟内存管理技术,每个进程都有各自独立的进程地址空间(即4G的线性虚拟空间),无法直接访问物理内存。这样起到保护操作系统,并且让用户程序可使用比实际物理内存更大的地址空间。
785
+
786
+ 4G进程地址空间被划分两部分,内核空间和用户空间。用户空间(包括代码、数据、堆、共享库以及栈)从0到3G,内核空间(包括内核中的代码和数据结构)从3G到4G;
787
+
788
+ 
789
+
790
+ 用户进程通常情况只能访问用户空间的虚拟地址,不能访问内核空间虚拟地址。只有用户进程进行系统调用(代表用户进程在内核态执行)等情况可访问到内核空间;
791
+ 用户空间对应进程,所以当进程切换,用户空间也会跟着变化;
792
+ 内核空间是由内核负责映射,不会跟着进程变化;内核空间地址有自己对应的页表,用户进程各自有不同额页表。
793
+
794
+ 从程序角度看,我们谈到的地址空间一般是虚拟地址空间,通过malloc或new分配的内存都虚拟地址空间的内存。虚拟地址空间与物理地址空间的都是以page为最小管理单元,page的大小因系统而异,一般都是4KB。虚拟地址空间有到物理地址空间的映射,如果要访问的虚拟地址空间没有映射到物理地址空间,操作系统会产生缺页中断,将虚拟地址空间映射到物理地址空间。
795
+
796
+ 因此,程度的虚拟地址空间比物理的地址空间要大的多。在较多进程同时运行时,物理地址空间有可能不够,操作系统会将一部物理地址空间的内容交换到磁盘,从而腾挪出一部分物理地址空间来。磁盘上的交换区,在linux上叫swap area,windows时叫page file。
797
+
798
+ android底层基于linux,不过android是没有交换区的(为什么没有?),所以android系统的内存资源就更加宝贵。为更合理、充分利用有限内存资源,android引入一个low-memory-killer机制,在内存不足,根据规则回收一部分低优先级的进程,从而释放他们占有的内存。
799
+
800
+ 进程的内存空间只是虚拟内存,而程序运行需要的是物理内存(ram),在必要时,操作系统会将程序运行中申请的虚拟内存映射到ram,让进程能够使用物理内存。进程所操作的空间都是虚拟地址空间,无法直接操作ram。java程序发生OOM并不表示ram不足,如果ram真的不足,android的memory killer就会发挥作用,它会杀死一些优先级比较低的进程来释放物理内存,让高优先级程序得到更多的内存。
801
+
802
+
781
803
Android系统给每个进程分配了一定的虚拟地址空间大小,进程使用的虚拟空间如果超过阈值,就会触发OOM。所以只可能是线程太多,消耗了大部分虚拟内存地址空间,从而引发了当前进程空间不足。
782
804
783
- [Virtual Memory and Linux](https://events.linuxfoundation.org/sites/events/files/slides/elc_2016_mem.pdf)
784
- [Android进程的内存管理分析](https://blog.csdn.net/gemmem/article/details/8920039)
805
+ `adb shell dumpsys meminfo packagename` 可以查看占用的内存信息
806
+ ```
807
+ PD1806:/system/bin $ dumpsys meminfo com.example.oom
808
+ Applications Memory Usage (in Kilobytes):
809
+ Uptime: 31807223 Realtime: 31807223
810
+
811
+ ** MEMINFO in pid 11380 [com.example.oom] **
812
+ Pss Private Private SwapPss Heap Heap Heap
813
+ Total Dirty Clean Dirty Size Alloc Free
814
+ ------ ------ ------ ------ ------ ------ ------
815
+ Native Heap 64227 64176 0 28 77824 72483 5340
816
+ Dalvik Heap 2158 2124 0 24 3590 2693 897
817
+ Dalvik Other 20804 20804 0 0
818
+ Stack 92 92 0 0
819
+ Ashmem 2 0 0 0
820
+ Gfx dev 892 892 0 0
821
+ Other dev 12 0 12 0
822
+ .so mmap 8595 212 6180 16
823
+ .apk mmap 2388 1964 60 0
824
+ .ttf mmap 105 0 0 0
825
+ .dex mmap 2375 176 552 0
826
+ .oat mmap 176 0 112 0
827
+ .art mmap 6796 6356 120 0
828
+ Other mmap 60 4 4 0
829
+ EGL mtrack 29808 29808 0 0
830
+ GL mtrack 3000 3000 0 0
831
+ Unknown 44350 44332 0 1
832
+ TOTAL 185909 173940 7040 69 81414 75176 6237
833
+
834
+ App Summary
835
+ Pss(KB)
836
+ ------
837
+ Java Heap: 8600
838
+ Native Heap: 64176
839
+ Code: 9256
840
+ Stack: 92
841
+ Graphics: 33700
842
+ Private Other: 65156
843
+ System: 4929
844
+
845
+ TOTAL: 185909 TOTAL SWAP PSS: 69
846
+
847
+ Objects
848
+ Views: 27 ViewRootImpl: 1
849
+ AppContexts: 5 Activities: 1
850
+ Assets: 7 AssetManagers: 0
851
+ Local Binders: 14 Proxy Binders: 31
852
+ Parcel memory: 4 Parcel count: 20
853
+ Death Recipients: 1 OpenSSL Sockets: 0
854
+ WebViews: 0
855
+
856
+ SQL
857
+ MEMORY_USED: 0
858
+ PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0
859
+ ```
860
+
861
+
862
+ - [Virtual Memory and Linux](https://events.linuxfoundation.org/sites/events/files/slides/elc_2016_mem.pdf)
863
+ - [Android进程的内存管理分析](https://blog.csdn.net/gemmem/article/details/8920039)
864
+ - [Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析](https://blog.csdn.net/luoshengyang/article/details/6939890)
865
+ - [Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析](https://blog.csdn.net/luoshengyang/article/details/6664554)
866
+ - [Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划](https://blog.csdn.net/luoshengyang/article/details/6651971)
867
+ - [虚拟内存那点事](https://sylvanassun.github.io/2017/10/29/2017-10-29-virtual_memory/ )
785
868
786
869
---
787
870
0 commit comments