06.Android内存泄露和内存溢出

📅 2026/7/14 20:21:10 👁️ 阅读次数 📝 编程学习
06.Android内存泄露和内存溢出

文章目录

  • Android 内存泄露和内存溢出
    • 1.Android 系统为每个 App 分配的内存有多大?
      • 总结
    • 2.内存分配 Demo

Android 内存泄露和内存溢出

内存泄漏:每创建一个对象,系统都会为其分配内存。当对象使用完毕后,Java 虚拟机会自动回收其所占内存。然而,如果代码中存在隐蔽的引用问题,导致某些对象虽然已不再使用、却仍被引用,Java 虚拟机便不会回收这些对象——这就是内存泄漏。

泄漏的对象不断累积,所占内存逐渐增大,一旦超过系统分配的上限,就会引发内存溢出。

内存溢出:App 的内存占用超过系统允许的最大上限值,导致程序无法继续分配内存,最终崩溃退出。

1.Android 系统为每个 App 分配的内存有多大?

Android 系统为每个应用分配的内存大小并非固定,而是动态调整的,具体取决于设备硬件、系统版本、厂商定制策略以及应用自身配置。以下是关键细节:

应用可用的内存主要分为两类:

  • Java 堆内存(重点):由 Java 虚拟机管理,用于存储 Java 对象,有明确的上限。
  • Native 内存:由操作系统直接分配,主要用于 C/C++ 代码和 Bitmap 等大数据对象,理论上没有严格上限(但受设备物理内存限制)。
  1. 默认内存限制(Java Heap)

不同时期和档次的设备,Java 堆内存上限差异较大:

  • 早期版本(Android 2.x~4.x): 单个应用的堆内存上限通常为 16MB~48MB(低端设备可能更低)。
  • 现代版本(Android 5.0+):
    • 中低端设备:64MB~128MB
    • 高端设备:256MB~512MB(部分旗舰机可达 1GB 以上)。
  1. 内存分配的影响因素

(1) 设备硬件

  • RAM 总容量:低端设备(2GB RAM)可能限制应用堆内存为 128MB,而高端设备(12GB+ RAM)可能允许 512MB 或更高。
  • 厂商定制:不同厂商(如小米、三星)可能调整内存策略,例如后台应用限制更严格。

(2) 系统版本

  • Android 8.0+:引入内存分级(low-memory、mid-memory、high-memory),动态调整应用限制。
  • Android 11+:强化后台应用内存限制,优先保障前台应用。

(3) 进程类型

  • 前台进程:优先级最高,可占用更多内存。
  • 后台进程:可能被严格限制(如压缩或回收)。
  1. 其他内存区域

除了 Java 堆内存,应用还可使用以下内存(但受系统总 RAM 限制):

  • Native 堆(C/C++ 分配):通过NDK分配的内存,不受 Java 堆限制,但过量使用仍会触发 OOM。
  • 显存(GPU):用于图形渲染,由系统共享管理。
  • 内存映射文件:如Bitmap可能直接映射到 Native 内存。
  1. 内存使用状态

可通过以下命令检测当前 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.heapsize
  • dalvik.vm.heapgrowthlimit:普通应用的默认最大堆内存(单位 KB)。

  • dalvik.vm.heapsize:启用android:largeHeap="true"时的更大堆内存限制

  1. 开发者建议
  • 优化内存使用

    • 使用LeakCanary等工具主动检测内存泄漏。
    • 对大对象(如Bitmap)采用缓存策略或采样压缩,避免一次性加载过大的图片。
  • 适配多设备

    • 务必在低内存设备(如 2GB RAM 手机)上进行测试,确保 App 在资源受限环境下也能稳定运行。
    • 实现onTrimMemory()回调,及时响应系统的内存警告,主动释放非必要资源。
  • 谨慎使用largeHeap:仅在确实需要大量内存的场景(如大型图像处理应用)中启用android:largeHeap="true",否则可能影响系统整体性能,甚至影响应用商店的审核。

总结

  • 典型值:现代设备上,普通应用的 Java 堆内存限制通常为 192MB~512MB。
  • 动态调整:实际内存上限由设备硬件、系统版本和厂商策略共同决定,并非固定不变。
  • 监控工具:优先使用Android Profileradb 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>

✨✨✨