【问题标题】:Logic behind memory leak in androidandroid中内存泄漏背后的逻辑
【发布时间】:2014-02-04 08:41:50
【问题描述】:

通常在 C++ 中什么是内存泄漏,如果我们分配了一个类似的对象

Obj c = new Obj();

如果我们这样做

c = b; (example)

我们丢失了指向对象c 的指针,这就是内存泄漏。

问题:

但在 android 垃圾收集器中,当没有指向它们的指针时收集对象。那么为什么即使在那之后还有内存泄漏呢?

更新

所有答案都指向对未使用对象的引用导致内存泄漏。这是正确的。但这是内存泄漏的唯一原因。除非它是静态的,否则当活动完成时将释放持有的指针。有位图和其他内存饥饿对象,它们不会造成任何问题

【问题讨论】:

标签: android memory


【解决方案1】:

在Android/Java中发生内存泄漏

  • 即使不再需要对象/实例的引用

  • 当你保持打开一个文件流时,当你完成它时。

  • 未关闭的连接

内存泄漏还有其他原因,但这些是most common ones

【讨论】:

    【解决方案2】:

    在垃圾回收运行时中,内存泄漏意味着即使不再使用对象也无法回收。例如,一个对象的引用被持有,但该引用不再用于任何事情。

    随意地,术语内存泄漏用于指代这些无法收集的对象不断累积、增加分配的堆大小并最终导致 OOM 的情况。

    【讨论】:

    • 如果实例变量较少,则不能处理。强引用并不指向内存泄漏(该术语是没有保持泄漏)。但我更频繁地听到术语内存泄漏。知道的人可以解释一下,我很想知道。
    【解决方案3】:

    当上下文(活动、服务等)被任何可以引用它的帮助类保留时,可能会发生泄漏。

    插图:而不是这个:

    public class Helper {
    
        private static Context mContext;
    
        public Helper(Context context){
    
            mContext = context;
        }
    
        public static void methodDoesSomething(){
    
            ...
        }
    }
    

    通过将上下文作为参数传递来使用上下文而不保留它:

    public class Helper {
    
        public static void methodDoesSomething(Context context){
            ...
        }
    }
    

    因为 Android 在某些时候会想要销毁一个 Activity,并且一个对象有一个对它的引用,所以垃圾收集器无法删除该 Activity,因此我们有内存泄漏。

    【讨论】:

      【解决方案4】:

      答案部分在您的问题中:正是因为这些引用没有被释放。假设您有一个类的实例,您已经结束了在其中的工作,但在某些情况下,该实例仍处于未释放的状态。除了垃圾收集器无法释放它之外,如果不加以控制,如果不加以处理,内存量甚至可能会增加。

      还有一件事。您可能有一个看起来正确且编写良好的代码,但是当您实例化一些本机库时,这意味着您正在引用类的层次结构。如果您不知道自己在做什么,您可能会错误地处理某些引用并导致内存泄漏。一个非常流行的例子是在你的类中保留一个Context 引用。上下文实例永远不会被释放,这是造成大量内存泄漏的原因。

      除了显而易见的(完成后的免费对象等)之外,还有其他解决方案。在 Java 中有SoftReferencesWeakReferences 等。这些对象是容器,告诉垃圾收集器它们在未使用或没有其他引用指向它们时优先释放。所以你正在帮助 GC 知道应该释放什么。它们在 Android 环境中的某个时刻是危险的,因为应用程序的堆被限制为 16MB,因此WeakReference 可能被收集得太快。需要检查对象是否还存在。

      【讨论】:

      • 是的,我读过那些东西,因为我们释放了指针,我们不需要担心这些对象的垃圾收集。我刚刚更新了我的问题
      • 更新基本上是引用了我的第二句话。它是关于实例化 Java/Android 原生类和调用类的层次结构。它们在未使用时应该被释放,但处理不当可能会导致内存泄漏。
      【解决方案5】:

      我认为我们首先需要定义“内存泄漏”。内存泄漏是您不再需要的东西,但它仍然在内存中,每次创建新对象时,都会在内存中分配一个新位置。应用程序将及时持有越来越多的内存。

      private static Drawable background;
      
      @Override
      protected void onCreate(Bundle state) {
        super.onCreate(state);
      
        TextView label = new TextView(this);
      
        background = getDrawable(R.drawable.large_bitmap);
      
        label.setBackgroundDrawable(background);
      
        setContentView(label);
      }
      

      上面的例子,TextView获取Activity作为参考,这是一个链接

      TextViewActivity

      现在,然后有一个静态变量

      背景

      保存背景可绘制的静态变量将一直存在,直到应用程序被销毁或完成。想象一下,您想销毁活动,当您销毁静态变量时,仍然会保留指向活动的链接,因为垃圾收集器将无法收集它。

      您可以查看here 了解更多信息。

      【讨论】:

      • 静态变量的范围是整个应用程序,不会导致任何内存泄漏。不是吗?但它会随着程序结束或进程死亡而释放。那么术语不同,为什么是内存泄漏。也感谢您的帮助
      • 我认为我们需要首先定义“内存泄漏”。内存泄漏是你不再需要的东西,但它仍然在内存中,每次你创建一个新的活动时,内存也会在内存中保存新的活动。在上面的例子中,你破坏了活动,这意味着你不希望它在你的记忆中,但它仍然存在,你实际上持有一个不应该存在的记忆。那应该是内存泄漏的定义。在您的示例中,GC 已经从堆中收集 c 值,这实际上不会导致任何内存泄漏。
      • 是的,保持引用是内存泄漏,但可以通过使用低范围对象来减少。但是还有其他因素会导致内存泄漏,由于我们不能像c++那样直接释放内存,所以可能有一些方法
      • 我忘了说真正的原因,老实说,每次你创建另一个activity,新activity都会在内存中占据另一个位置,如你所见,你会分配比以前更多的内存,所以继续,越来越多,这是内存泄漏。
      • 对不起,我没有明白这一点。当我们为每个活动连续分配内存时,您的意思是总和增加了还是每次分配都奇怪地增加了?
      猜你喜欢
      • 2011-12-31
      • 1970-01-01
      • 1970-01-01
      • 2020-07-13
      • 2012-11-14
      • 2014-08-05
      • 2015-07-20
      • 2013-08-23
      相关资源
      最近更新 更多