Android 变量生命周期、变量内存释放机制、GC触发时机研究、内存优化建议_background young concurrent copying gc freed(1)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

Android的GC机制是可达性回收,具体本文就不再具体阐述了,本文只分析android系统什么时候会触发GC,以及监听Object对象被回收的时机:
作者:大鼓书;链接:https://www.jianshu.com/p/57d8306c4eae

全局变量与局部变量

先看下面的代码的注释,先明白我说的全局变量 局部变量 说的是什么意思:

class DetailActivity : AppCompatActivity() {
//这个house就是全局变量
private var house: House? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
//这个person就是局部变量
val person = Person()
}

findViewById(R.id.button).setOnClickListener { v->
//这个person2就是局部变量
person2 = Person()
Log.e(“dq”,"create Person "+person2!!.hashCode());
}
}

  • Activity中定义的全局变量,如果不为null,那么只能在 Activity 的onDestory()的5秒后被GC释放内存,xml里的View的内存机制也是一样 无论你有没有把View设置为全局变量
  • Activity中定义的全局变量如果被你 = null,那么他的生命周期和局部变量是一样的,都是在触发GC的时候会释放内存
  • 很多手机,你用代码主动调用System.gc() 毫无效果
  • 如果内存不紧张,那么系统会在当前Activity走了生命周期方法(比如onPause、onDestory)后再过5、6秒触发GC(onDestory后5秒是一定会GC的,home回到桌面会走onPause再过5秒也会GC。但是再回来走onResume就不GC了)
  • onDestory的5秒后触发了GC,Activity和全局变量才彻底被回收(即:WeakReference.get() == null)
  • 系统触发GC有时候会在logcat里打印,有时候不会,虽然GC会 stop 所有线程,但是简单的GC 的pause的时长只有5ms,0.0004秒

com.dq.qkotlin: Background young concurrent copying GC freed 58306(1766KB) AllocSpace objects, 4(68KB) LOS objects, 32% free, 3959KB/5892KB, paused 5.216ms total 23.590ms

  • 所以GC比你想象中频繁的多
  • 如果你的Object比较简单,里面就包含几个String,int。那么这个Object占用的内存非常少,10000个Object只占用2M的内存,我当时轮询创建了1000多个局部变量Object,都没触发系统GC。也就是说这1000多个局部变量Object都在内存里没释放
  • 即便如此,还是不建议你疯狂的创建局部变量,因为可能出现无连续可用内存而导致oom
  • 如果你创建的局部变量非常大,就会"惊动"系统,系统会主动触发GC来回收局部变量

意外发现

如果来回频繁的上下滚动RecyclerViewListView(即便滚动的距离非常短,没触发ViewHolder的复用)。就仅仅是手指在屏幕上快速的上下戳动10秒左右,也会触发GC(而且当时我并没有new Object()

这是唯一我发现的 Activity生命周期没改变内存占用不紧张 的情况下也会触发GC的场景,推测可能是android底层自己处理的。

存储同样的数据,HashMap的内存占用约等于Model的3倍,我原本以为会是17倍左右,毕竟他底层是个int[16] 。但是实际测试只是3倍左右

//每调用一次创建十万个对象,检测内存变化
for (int i = 0; i < 100000; i++) {
linklist.add(new Object()); //内存变化:73M - 76M - 79M - 82M
linklist.add(new HashMap<String,String>()); //内存变化:79M - 85M - 91M

GiftBean bean = new GiftBean();
bean.setTitle(“1”);
linklist.add(bean); //71M - 77M - 83M - 88M - 94M = 每次差额为6M

HashMap<String,String> map = new HashMap<String,String>();
map.put(“title”,“1”);
linklist.add(map); //72M - 88M - 105M - 121M = 每次差额为17M
}

如何监听变量生命周期?

class Person : Object() {

var name: String? = null

//走了finalize方法就说明该Object被回收了
@kotlin.jvm.Throws(Throwable::class)
override fun finalize() {
Log.e(“dq”,"Person 被回收 " +hashCode())
}
}

如何监听系统GC?

public class GcWatcherInternal {

private static WeakReference sGcWatcher;

private static ArrayList sGcWatchers = new ArrayList<>();
private static Object lock = new Object();

private static final class GcWatcher {
@Override
protected void finalize() throws Throwable {
sLastGcTime = SystemClock.uptimeMillis();
ArrayList sTmpWatchers;
synchronized (lock) {
sTmpWatchers = sGcWatchers;
try {
for (int i = 0; i < sTmpWatchers.size(); i++) {
if (sTmpWatchers.get(i) != null) {
sTmpWatchers.get(i).run();
}
}
} catch (Throwable e){
e.printStackTrace();
}
sGcWatcher = new WeakReference<>(new GcWatcher());
}
}
}

public static void addGcWatcher(Runnable watcher) {
synchronized (lock) {
sGcWatchers.add(watcher);
if(sGcWatcher==null)
sGcWatcher = new WeakReference<>(new GcWatcher());
}
}
}

//MainActivity中写一次就好
GcWatcherInternal.addGcWatcher { Log.e(“dq”,“触发GC !!!”) }

怎么优化内存

网上别人写的什么bitmap、handle内存泄漏、静态单例 一堆乱七八糟的东西,我在这里就不写了。我就只针对上述我自己的研究成果说一下我自己的看法

在Activity\Fragment中,无论你是否把View设为全局变量,View的生命周期都是一样的。所以性能和内存占用是一样的。

结语

网上高级工程师面试相关文章鱼龙混杂,要么一堆内容,要么内容质量太浅, 鉴于此我整理了上述安卓开发高级工程师面试题以及答案。希望帮助大家顺利进阶为高级工程师。
目前我就职于某大厂安卓高级工程师职位,在当下大环境下也想为安卓工程师出一份力,通过我的技术经验整理了面试经常问的题,答案部分是一篇文章或者几篇文章,都是我认真看过并且觉得不错才整理出来。

大家知道高级工程师不会像刚入门那样被问的问题一句话两句话就能表述清楚,所以我通过过滤好文章来帮助大家理解。

1307页字节跳动Android面试真题解析火爆全网,完整版开放下载

现在都说互联网寒冬,其实只要自身技术能力够强,咱们就不怕!我这边专门针对Android开发工程师整理了一套【Android进阶学习视频】、【全套Android面试秘籍】、【Android知识点PDF】。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

做到真正的技术提升。**

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-gAb6nNrc-1713669198653)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 22
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值