【问题标题】:How to handle memory Leaks while continuous insertion in a LinkedList?连续插入LinkedList时如何处理内存泄漏?
【发布时间】:2012-04-22 11:21:15
【问题描述】:

我有以下函数,该函数从连续运行的线程的 run() 中连续调用。

private LinkedList<short[]> playerData = new LinkedList<short[]>();

public synchronized void setPlayerData(short[] buffer) {
        // Log.i(LOG_TAG, "Inside setData..");
        playerData.addLast(buffer);
        if (playerData.size() > 10) {
            // Log.i(LOG_TAG, "playerData not empty");
            playerData.removeFirst();
        }
    }

现在 DDMS 的 allocation Tracker 说很多对象是在 addLast() 内部创建的(实际上是在 addLastImpl() 内部),因此我想明确删除这些数组,以便它们是堆中总是有足够的内存。现在,

  1. System.gc() 选项没有帮助,因为它会在每次调用 setPlayerData() 时同时被调用。
  2. GC_CONCURRENT 正在占用所有 CPU 周期,因为应用程序对时间非常敏感,即使是几毫秒的延迟也是不可接受的。

有关 LogCat 信息,请参阅link,这是我针对整个 synarion 提出的另一个问题。在这个线程中,我只是试图通过将其划分为一组小问题来解决更大的问题。

一种可能的解决方案 一种可能的解决方案是通过删除不需要的数组来显式释放内存空间。但是在 Java 中,我们如何释放由 new 运算符创建的数组?即

short[] buffer = new short[320];
// do some operation on buffer
/// now how can I explicitly free memory by deleting the buffer, when its job is over..

我知道有垃圾收集来处理所有这些事情。但在我的应用中,GC_CONCURRENT 一直在吃光。其他进程因此而被饿死。如果我能够显式释放内存,即在 C++ 中删除,那就太好了。可以在这里查看LogCat信息...A detailed question regarding my problem

编辑 2 3.将数组赋值为null

这有什么帮助?空数组将被安排到垃圾收集中,这是我想避免的,因为该方法是从一个线程连续调用的(每 20 毫秒)。如果我将数组分配为 null,GC_FOR_MALLOC 消息将填充 LogCat...

【问题讨论】:

  • 很难理解你到底想要什么。问题是什么?如果问题真的是在询问减少 Android 应用程序中的内存使用量,为什么标题会要求“等同于 C++ 中的 'delete' 运算符”?
  • @AlexLockwood:如果有什么要释放的数组,我可以删除不需要的数组..以减少内存泄漏..
  • addLast() 中分配的唯一对象是一个Entry 对象,用于保存链接和对数组的引用。当您调用removeFirst() 时,该对象最终将被释放到 GC。我怀疑你这里有真正的问题。
  • @EJP removeFirst 仅在 size > 10 时调用,并且分配跟踪器显示 addLast() 正如我在问题中提到的那样。我怀疑你是否完整地阅读它......

标签: java android memory-leaks garbage-collection


【解决方案1】:

你的问题不会通过显式删除对象来解决......基本上是因为在 Java 中没有办法做到这一点。

如果您真的为 CMS 收集器创建了太多垃圾来处理,那么唯一的解决方案是使用对象池来回收 buffer 对象而不是将它们丢弃在地板上供 GC 处理。但是,您需要注意不要用其他人替换您当前的问题:

  • 回收的对象可能需要“清理”(归零)。
  • 设计不佳的对象池可能会导致内存泄漏。
  • 设计不佳的对象池可能会成为并发瓶颈。
  • 设计不佳的对象池可能会增加 GC 开销,尤其是在使用太小的堆运行时。

另一方面,您真正的问题可能是您的堆对于您尝试运行的应用程序来说太小了。如果你跑得太接近极限,GC 每次都不会回收很多垃圾。由于运行 GC 的成本与 NON-garbage 的数量成正比,因此很容易看出,随着堆接近满,GC 的效率是非线性的。

【讨论】:

  • +1,谢谢你这么好的回答......我真的会去对象池......我一定会记住你的指导方针......谢谢你先生......
  • @rahul - 在你这样做之前,明智检查问题是否真的是堆太小。
【解决方案2】:

使用后只需将您的对象设置为 NULL垃圾收集器会自动处理它。实际上,当代码无法访问您的对象时,垃圾收集器就会启动,因此它会销毁它们以释放空间。

【讨论】:

  • 你不能简单地将你的数组设置为 null 吗?
  • 这有什么帮助?空数组将被安排到垃圾收集中,我想避免这种情况,因为该方法是从一个线程连续调用的(每 20 毫秒)。如果我将数组分配给 null,GC_FOR_MALLOC 消息将填充 LogCat...
  • 在全局级别定义一个数组并在您的代码中重新使用它。这样做会导致不分配更多内存,并让 GC 远离。
  • 我想你不知道垃圾收集器是如何工作的。当您的对象不可访问时,GC 不会“实际启动”。我建议您阅读有关 GC 的内容。有几件事会触发次要/主要/完整 GC,但当对象不再可访问时不会发生任何事件。
【解决方案3】:

Java 没有删除操作符。当代码部分不再使用对象时,垃圾收集器会自动销毁对象。

当一个对象变得不可访问时,垃圾收集器会销毁该对象并释放相关的内存。

我阅读了编辑,也许您可​​以使用 byte[] 缓冲池解决您的问题。所以垃圾收集器不需要一直对缓冲区进行垃圾处理。

私有链表 playerData = new LinkedList();

public synchronized void setPlayerData(short[] buffer) {
  // Log.i(LOG_TAG, "Inside setData..");
  playerData.addLast(buffer);
  if (playerData.size() > 10) {
    // Log.i(LOG_TAG, "playerData not empty");
    byte[] buffer = playerData.removeFirst();
    // here return the buffer to the pool to reuse it
  }

  }

【讨论】:

  • 我知道,有什么办法可以显式释放内存吗?
  • 为变量赋空值
【解决方案4】:

如果您在使用垃圾收集器时遇到问题,最好的办法是分配更少的新内存。一种方法是使用object pools。基本上,重复使用不再需要的缓冲区,而不是创建新缓冲区。

【讨论】:

  • 我认为我的回答仍然相关。不要使用 add,不要使用 remove,尝试重复使用你拥有的东西。
【解决方案5】:

Java 中没有“等价”运算符。系统在后台执行垃圾收集。没有显式的方法调用可以保证立即释放内存。

【讨论】:

    猜你喜欢
    • 2018-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-14
    • 2017-08-11
    • 1970-01-01
    相关资源
    最近更新 更多