内存分配与回收

无论是在移动设备还是传统PC,内存的使用都是需要关注的一块。特别是在Android上,内存使用不当容易导致内存泄漏,影响App的性能。

内存分配

在Java中,内存是分代管理的,比如新创建的对象,他被放在了Young Generation。JVM的书籍中一般会都会介绍内存模型,分配等,下面我们简单回顾一下。

  • 年轻代( Young Generation): 包含Eden,S0,S1
  • 老年代(Old Generation): Minor GC之后迁入
  • 永久代(Permenent Generation ): ClassLoader,Class等

不同代之间的差异主要是体现在对象的存活时间上:

  • Eden,新创建的对象存放;
  • S0/S1,幸存对象,Eden满后,触发Minor GC,幸存的对象已入S0中,S0满后,触发Minor GC,幸存对象放入S1中,任何时候S0、S1有一个是空的;
  • 老年代,多次Minor GC后依然存活的对象(比如15轮GC),放入老年代;
  • 老年代满后,触发Major GC,存活的放入永久代
  • Major GC相比Minor GC,更加耗时;
  • Major GC发生在老年代和永久代

// TODO

了解内存模型有助于我们更好的理解Java代码的执行,比如我们应该避免在循环体内大量创建临时对象,因为这会导致年轻代触发大量GC。

垃圾回收

现在我们知道,内存模型是分代管理,分配的,那么问题来了;

  1. 为甚么要分代管理内存,搞一个大块不是更简单么?
  2. 每一块内存满了之后触发的垃圾回收是怎么样的呢?

第一个问题,笔者是这么认为的:内存分代,是因为在程序中对象的存活时间是不一致的,很多对象创建完了很快就不需要使用了,比如说一次性手套,用完就丢了(回收了)。但是有些对象却存活很久,有可能伴随整个程序的生命周期。所以为了更高效的管理内存,更快回收未被使用的内存,分代是一个较好的策略。

第二个问题,每一块内存满了之后,根据不同代的特性,可以采用不同的垃圾回收算法, 下面我们简单了解下几个经典的回收算法。

  • 标记清除法/标记压缩法 (Mark and Sweep)
  • 复制收集算法 (Copy and Collection)
  • 引用计数法 (Reference Count)

在Android开发中,做Java后端的开发者可能会需要根据业务场景进行JVM调优,但是做Android开发实际上是不需要做参数调优的。Andorid使用的不是JVM,而是DVM,而且官方也没有公开提供接口给开发者来设置每个app的虚拟机参数,我们了解虚拟机的垃圾回收只是作为理解。

在执行app的时候,日志终端经常会出现一些GC的日志,这些就是Android平台下发生GC的体现,我们更多的是根据日志来推断当前App是否频繁回收垃圾,是否内存不足。

TODO

  • 共享、私有内存
  • GC

查看某个java进程的内存与gc情况

  1. ps -eaf |grep java
  2. jstat -gc [pid] [ 1000]
  • 内存使用量
adb shell dumpsys meminfo 10821

参考

powered by Gitbook更新: 2018-04-02

results matching ""

    No results matching ""