06.Android内存泄露和内存溢出
文章目录
- Android 内存泄露和内存溢出
- 1.Android 系统为每个 App 分配的内存有多大?
- 总结
- 2.内存分配 Demo
Android 内存泄露和内存溢出
内存泄漏:每创建一个对象,系统都会为其分配内存。当对象使用完毕后,Java 虚拟机会自动回收其所占内存。然而,如果代码中存在隐蔽的引用问题,导致某些对象虽然已不再使用、却仍被引用,Java 虚拟机便不会回收这些对象——这就是内存泄漏。
泄漏的对象不断累积,所占内存逐渐增大,一旦超过系统分配的上限,就会引发内存溢出。
内存溢出:App 的内存占用超过系统允许的最大上限值,导致程序无法继续分配内存,最终崩溃退出。
1.Android 系统为每个 App 分配的内存有多大?
Android 系统为每个应用分配的内存大小并非固定,而是动态调整的,具体取决于设备硬件、系统版本、厂商定制策略以及应用自身配置。以下是关键细节:
应用可用的内存主要分为两类:
- Java 堆内存(重点):由 Java 虚拟机管理,用于存储 Java 对象,有明确的上限。
- Native 内存:由操作系统直接分配,主要用于 C/C++ 代码和 Bitmap 等大数据对象,理论上没有严格上限(但受设备物理内存限制)。
- 默认内存限制(Java Heap)
不同时期和档次的设备,Java 堆内存上限差异较大:
- 早期版本(Android 2.x~4.x): 单个应用的堆内存上限通常为 16MB~48MB(低端设备可能更低)。
- 现代版本(Android 5.0+):
- 中低端设备:64MB~128MB
- 高端设备:256MB~512MB(部分旗舰机可达 1GB 以上)。
- 内存分配的影响因素
(1) 设备硬件
- RAM 总容量:低端设备(2GB RAM)可能限制应用堆内存为 128MB,而高端设备(12GB+ RAM)可能允许 512MB 或更高。
- 厂商定制:不同厂商(如小米、三星)可能调整内存策略,例如后台应用限制更严格。
(2) 系统版本
- Android 8.0+:引入内存分级(low-memory、mid-memory、high-memory),动态调整应用限制。
- Android 11+:强化后台应用内存限制,优先保障前台应用。
(3) 进程类型
- 前台进程:优先级最高,可占用更多内存。
- 后台进程:可能被严格限制(如压缩或回收)。
- 其他内存区域
除了 Java 堆内存,应用还可使用以下内存(但受系统总 RAM 限制):
- Native 堆(C/C++ 分配):通过
NDK分配的内存,不受 Java 堆限制,但过量使用仍会触发 OOM。 - 显存(GPU):用于图形渲染,由系统共享管理。
- 内存映射文件:如
Bitmap可能直接映射到 Native 内存。
- 内存使用状态
可通过以下命令检测当前 App 的内存使用状态:
adb shell dumpsys meminfo<package_name>以下命令可查询当前设备上单个应用可分配的最大内存限制(主要是 Java 堆内存):
# Mac shelladb shell getprop|grepdalvik.vm.heapgrowthlimit# Windows shelladb shell getprop|findstr dalvik.vm.heapgrowthlimit# Mac shelladb shell getprop|grepdalvik.vm.heapsize# Windows shelladb shell getprop|findstr dalvik.vm.heapsizedalvik.vm.heapgrowthlimit:普通应用的默认最大堆内存(单位 KB)。dalvik.vm.heapsize:启用android:largeHeap="true"时的更大堆内存限制。
- 开发者建议
优化内存使用:
- 使用
LeakCanary等工具主动检测内存泄漏。 - 对大对象(如
Bitmap)采用缓存策略或采样压缩,避免一次性加载过大的图片。
- 使用
适配多设备:
- 务必在低内存设备(如 2GB RAM 手机)上进行测试,确保 App 在资源受限环境下也能稳定运行。
- 实现
onTrimMemory()回调,及时响应系统的内存警告,主动释放非必要资源。
谨慎使用
largeHeap:仅在确实需要大量内存的场景(如大型图像处理应用)中启用android:largeHeap="true",否则可能影响系统整体性能,甚至影响应用商店的审核。
总结
- 典型值:现代设备上,普通应用的 Java 堆内存限制通常为 192MB~512MB。
- 动态调整:实际内存上限由设备硬件、系统版本和厂商策略共同决定,并非固定不变。
- 监控工具:优先使用
Android Profiler和adb shell dumpsys meminfo来分析和监控应用的内存使用情况。
2.内存分配 Demo
classMemoryDemoActivity:AppCompatActivity(){privatelateinitvarbinding:ActivityMemoryDemoBindingprivatevarclickCount=0privatevalmemoryHolders=mutableListOf<ByteArray>()overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)enableEdgeToEdge()binding=ActivityMemoryDemoBinding.inflate(layoutInflater)setContentView(binding.root)ViewCompat.setOnApplyWindowInsetsListener(binding.main){v,insets->valsystemBars=insets.getInsets(WindowInsetsCompat.Type.systemBars())v.setPadding(systemBars.left,systemBars.top,systemBars.right,systemBars.bottom)insets}setupClickListener()updateMemoryInfo()}privatefunsetupClickListener(){binding.btnAllocateMemory.setOnClickListener{allocateMemory()clickCount++updateMemoryInfo()}}privatefunallocateMemory(){// 每次分配50MB的内存valmemoryChunk=ByteArray(10*1024*1024)memoryHolders.add(memoryChunk)binding.tvMaxMemory.setTextColor(getColor(android.R.color.black))}privatefunupdateMemoryInfo(){valruntime=Runtime.getRuntime()valmaxMemory=runtime.maxMemory()/(1024*1024)valusedHeapMemory=(runtime.totalMemory()-runtime.freeMemory())/(1024*1024)valnativeMemory=Debug.getNativeHeapAllocatedSize()/(1024*1024)binding.tvMaxMemory.text="最大可用内存:${maxMemory}MB"binding.tvHeapMemory.text="Java堆内存使用:${usedHeapMemory}MB"binding.tvNativeMemory.text="Native内存使用:${nativeMemory}MB"}}<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center_horizontal"tools:context=".demo.memory.MemoryDemoActivity"><Buttonandroid:id="@+id/btnAllocateMemory"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="32dp"android:text="分配内存"/><TextViewandroid:id="@+id/tvMaxMemory"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="32dp"android:textSize="16sp"tools:text="最大可用内存:1024MB"/><TextViewandroid:id="@+id/tvHeapMemory"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:textSize="16sp"tools:text="Java堆内存使用:512MB"/><TextViewandroid:id="@+id/tvNativeMemory"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:textSize="16sp"tools:text="Native内存使用:256MB"/></LinearLayout>✨✨✨
