Android什么时候会释放一个对象

人匠黄昏 暂无 Android开发  2017-12-09 08:48:46
如果我在 Activity中声明了一个变量(假设为一个接口的实现对象) , 这个变量是引用的单例对象中的一个实现对象 , 这个时候如果我关闭activity的时候不把这个变量==null的话会不会造成内存泄漏 ;

如果我这个变量引用的是一个长期运行的service或者是Application中的一个对象 , 会不会造成这个activity在整个app的生命周期中一直无法被释放 ;

我的理解是当前对象不持有其他对象的引用并且不被其他对象持有的时候会被释放掉 , 但是这个引用和持有具体是怎么算的我不太清楚 ;

常见的内存泄漏的情况一般就是在一个类中(包括Activity , Fragment , Service , BroadcastReceiver等) 创建了一个对象 , 然后这个对象被其他的类那去用了 , 那么那个类没用完的时候这个被引用了对象的类也不会被释放 , 那么如果一个类引用了一个生命周期更长的类中的对象的话 , 那么会不会造成声明周期短一些的类无法被回收导致内存泄漏 , 如果两个类之间有循环引用的情况 , 会不会导致这两个类在App的生命周期中始终无法被回收 ;
...全文
360 10 点赞 打赏 收藏 举报
写回复
10 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
xiaohuh421 2017-12-20
只要理解java回收机制原理, 这些问题就不会有了. 对于一个java对象, 是通过引用计数来确定是否有引用的, 多一次传递就会多一次引用. 如 =号赋值, 通过函数参数传递 等, 会增加引用计数. 引用变量的生命周期到达时, 会减少引用计数. 如函数局部变量在函数结束时, 或者对象的属性, 在对象被销毁时. 当引用计数变0, 则gc会在需要内存的时候回收它. 所以, 楼主的问题就好解答了. 当一个对象的引用计数为0, 即没有任何地方引用它时, 它本身就会被标记为可释放状态. 但内部属性会减少引用计数. 注意: 仅是标记 而已, 并不会马上释放, 具体释放时间, 是要看GC的.
  • 打赏
  • 举报
回复
人匠黄昏 2017-12-15
引用 3 楼 dalor 的回复:
就算是弱引用或长时间未使用的,都是由系统自己去释放和回收,时机也不可控。不像IOS可以手动释放,系统回收也比较好。
呃 , 如果按照实际来说的话 , ClassA持有一个存在时间更长的ClassB中的一个成员变量的引用 , 然后当A没有其他外部引用用到它的时候它会不会被释放掉啊 , 不考虑gc回收的时间差的话 ;
  • 打赏
  • 举报
回复
就算是弱引用或长时间未使用的,都是由系统自己去释放和回收,时机也不可控。不像IOS可以手动释放,系统回收也比较好。
  • 打赏
  • 举报
回复
人匠黄昏 2017-12-15
引用 1 楼 xiaohuh421 的回复:
持有只是一个概念. 可能一般理解为强引用. 强引用的话肯定是不能释放的.
你好 , 是否是包含了强引用的双方(如 ClassA.SetData(ClassB.Instance().getData2() 中的ClassA和ClassB ))都不会被释放 , 即使其中一方(如前面例子中的 ClassA使用完成 , 但是B还没有使用完 , 这时候A中还有B中一个对象的强引用 )已经使用完成 , 不手动把引用的地方置空(ClassA.SetData(null) )就会导致内存泄漏 ;
  • 打赏
  • 举报
回复
只为搞笑 2017-12-15
引用 8 楼 u010668114 的回复:
[quote=引用 7 楼 yjs1043014961 的回复:] [quote=引用 6 楼 u010668114 的回复:] 你可以了解一下GC回收变量的准则,目前的ART或者DALVIK虚拟机都是标记算法, 标记算法就是GC时,根据沿着这个程序的所有根对象遍历所有对象引用的子对象,把这些对象标记成不回收,剩下的没被标记到的就是要被回收的(这只是个大致逻辑,实际更复杂)。你想想,A要是没被引用会被标记到么。
之前我从ActivityA -> ActivityB , 在B中用代码加载了一个比较大的Bitmap作为成员变量 , 然后在B中定义了一个成员变量 C = D.Instance.getData() ; 我分别获取并查看了刚打开App , 进入B后和从B返回A时的内存占用和堆栈信息 , 从B返回A后内存被释放 , 可以肯定地说是bitmap被释放掉了 , 但是这时候堆栈信息中还是有C , 不知道是什么原因 ; 今晚回家我发一下当时的截图 ; [/quote] 首先,GC过程很复杂,并不是界面打开关闭就会GC,当然你手动GC除外。其次这个C只是一个引用(可以把它想成地址,并不占用什么空间),这个变量实际是被D的实例引用着的。你的D要是是个单例类的话,那这个变量肯定不会被回收掉的。[/quote] 这里我说的不准确,只是猜测这个变量被D引用着的,如果只是通过D的方法生成的一个对象的话,你可以手动GC后再看看内存信息
  • 打赏
  • 举报
回复
只为搞笑 2017-12-15
引用 7 楼 yjs1043014961 的回复:
[quote=引用 6 楼 u010668114 的回复:] 你可以了解一下GC回收变量的准则,目前的ART或者DALVIK虚拟机都是标记算法, 标记算法就是GC时,根据沿着这个程序的所有根对象遍历所有对象引用的子对象,把这些对象标记成不回收,剩下的没被标记到的就是要被回收的(这只是个大致逻辑,实际更复杂)。你想想,A要是没被引用会被标记到么。
之前我从ActivityA -> ActivityB , 在B中用代码加载了一个比较大的Bitmap作为成员变量 , 然后在B中定义了一个成员变量 C = D.Instance.getData() ; 我分别获取并查看了刚打开App , 进入B后和从B返回A时的内存占用和堆栈信息 , 从B返回A后内存被释放 , 可以肯定地说是bitmap被释放掉了 , 但是这时候堆栈信息中还是有C , 不知道是什么原因 ; 今晚回家我发一下当时的截图 ; [/quote] 首先,GC过程很复杂,并不是界面打开关闭就会GC,当然你手动GC除外。其次这个C只是一个引用(可以把它想成地址,并不占用什么空间),这个变量实际是被D的实例引用着的。你的D要是是个单例类的话,那这个变量肯定不会被回收掉的。
  • 打赏
  • 举报
回复
人匠黄昏 2017-12-15
引用 6 楼 u010668114 的回复:
你可以了解一下GC回收变量的准则,目前的ART或者DALVIK虚拟机都是标记算法, 标记算法就是GC时,根据沿着这个程序的所有根对象遍历所有对象引用的子对象,把这些对象标记成不回收,剩下的没被标记到的就是要被回收的(这只是个大致逻辑,实际更复杂)。你想想,A要是没被引用会被标记到么。
之前我从ActivityA -> ActivityB , 在B中用代码加载了一个比较大的Bitmap作为成员变量 , 然后在B中定义了一个成员变量 C = D.Instance.getData() ; 我分别获取并查看了刚打开App , 进入B后和从B返回A时的内存占用和堆栈信息 , 从B返回A后内存被释放 , 可以肯定地说是bitmap被释放掉了 , 但是这时候堆栈信息中还是有C , 不知道是什么原因 ; 今晚回家我发一下当时的截图 ;
  • 打赏
  • 举报
回复
只为搞笑 2017-12-15
你可以了解一下GC回收变量的准则,目前的ART或者DALVIK虚拟机都是标记算法, 标记算法就是GC时,根据沿着这个程序的所有根对象遍历所有对象引用的子对象,把这些对象标记成不回收,剩下的没被标记到的就是要被回收的(这只是个大致逻辑,实际更复杂)。你想想,A要是没被引用会被标记到么。
  • 打赏
  • 举报
回复
只为搞笑 2017-12-15
引用 4 楼 yjs1043014961 的回复:
[quote=引用 3 楼 dalor 的回复:] 就算是弱引用或长时间未使用的,都是由系统自己去释放和回收,时机也不可控。不像IOS可以手动释放,系统回收也比较好。
呃 , 如果按照实际来说的话 , ClassA持有一个存在时间更长的ClassB中的一个成员变量的引用 , 然后当A没有其他外部引用用到它的时候它会不会被释放掉啊 , 不考虑gc回收的时间差的话 ;[/quote] A会被回收,GC回收的标准比较复杂,但是在gc的时候可以确定被回收掉的就是没有被引用到的变量。这个和这个变量里引用了哪些变量没关系
  • 打赏
  • 举报
回复
xiaohuh421 2017-12-13
持有只是一个概念. 可能一般理解为强引用. 强引用的话肯定是不能释放的.
  • 打赏
  • 举报
回复
相关推荐
发帖
Android
加入

7.9w+

社区成员

移动平台 Android
申请成为版主
帖子事件
创建了帖子
2017-12-09 08:48
社区公告
暂无公告