持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
Android 内存类型
随机存取存储器 (Random Access Memory) - RAM
- RAM 用于在应用程序运行时进行临时存储。
- 在这里,应用程序是指在前台运行的应用程序和在后台运行的应用程序。
- 这是暂时的,因此当应用程序死机或设备重新启动时信息会丢失。
内存 - zRom
- 作为 RAM 的一部分,未使用的资源被压缩并移动到保留区域以增加可用内存量。
- 此压缩过程需要 CPU 上的更多工作,这会减慢设备运行速度。
存储器 - Storage
- 您的数据、照片、视频、音乐、文档等应该在设备重启后仍然存在。
- 示例包括 SharedPreference 、 SQLite 、 Realm 等。
- Android 的存储空间各不相同,但今天的存储空间一般为 32GB、64GB、128GB 和 256GB,可以相当大。
- 您还可以通过 microSD 卡等进一步扩展它。
内存管理过程由 Android Runtime (ART) 和之前的版本 Dalvik Virtual Machine 执行。
什么是内存泄漏
现在,我们需要知道为什么会发生内存泄漏,但在此之前,我们需要回想一下 JVM 是如何使用从操作系统接收到的内存的。
Android 使用 GC(Garbage Collector)来检索在堆区创建的对象。通过跟踪堆区域并从堆区域中检索不再使用的对象,留下内存区域。那么,如果你想一想,如果我们一直在堆中维护一个未使用的对象,GC 会认为该对象仍在使用中,而不是垃圾。这意味着无法从内存中释放对象,此时就会发生内存泄漏。如果不能一一删除这些数据,有时UI会变卡顿,app崩溃,就会出现OutOfMemory。
现在,让我们考虑一下,将它替换为 Android,因为我们以 Java 为例。有一个应用程序只有一个 TestActivity。
class TestActivity : AppCompatActivity(){
override onCreate(savedStateInstance : Bundle?) {
// 逻辑处理
}
}
在这种情况下,由于没有创建其他线程,所以只存在主线程,即 UI 线程。那么,在MainThread的JVMStack区域中,应该有一个TestActivity
类的值。TestActivity
的实现是在堆区域中,而不是值,具有实际对象值的按值调用类型,并且 JvmStack 将只有地址值,即 TestActivity
类的地址。
那么,其他各种Context
或组成这些活动的其余对象也将在堆栈上(在 MainThread 堆栈中)
class SingletonTest(context : Context) {
private var mContext = context
companion object{
var instance : SingletonTest? = null
fun getSingleton(context : Context) : SingletonTest {
if(instance == null) {
instance = SingletonTest(context)
}
return instance as SingletonTest
}
}
}
让我们像这样创建一个名为 SingletonTest
的类,以便我们可以接收单例形式的 Context。(这只是一个例子)
class TestActivity : AppCompatActivity(){
override onCreate(savedStateInstance : Bundle?) {
val singleton = SingletonTest.getSingleton(this)
}
}
这里隐藏了一个叫singleton的对象,从 TestActivity 调用 SingletonTest 的那一刻起,SingletonTest 就有了 TestActivity 的上下文,即使 TestActivity 死掉了,在 JVMStack 区域中引用的东西消失了,并且作为一个目标被包含在 GC 中,该实例仍然是被 TestActivity 引用。它被认为在使用,无法回收,这种情况会导致内存泄漏。