【问题标题】:Java memory leak when using an array使用数组时的 Java 内存泄漏
【发布时间】:2015-02-24 15:14:14
【问题描述】:

想证实我的假设。我正在查看另一个开发人员的代码,该开发人员正在使用数组(不是linkedhashset/排序集合等),并试图根据插入对其进行排序,同时保持它的大小固定。保持它固定大小的逻辑是从数组中删除最旧的项目。但是,当从数组中删除最旧的项目时,对象引用并没有被清空,即只有数组索引被写入另一个对象。我认为这可能会让旧的(未清空的)对象在内存中停留的时间比需要的时间长(如果不是完全内存泄漏的话),除非我错过了范围界定的任何内容。任何想法(我也在尝试通过快速测试和 visualvm 来确认)。提前致谢。

public class MemTest {

     private TestBuffer testQuotes = new TestBuffer(10);  //static inner class 


     public static void main(String[] args) {

         System.out.println("Starting!");
         MemTest memTest = new MemTest();
        for (int j = 0; j < 10; j++) { 
             for (int i = 0; i < 2000000000; i++) {
                 memTest.testQuotes.push(1, 12.3);
             }

             try {
                 Thread.sleep(2000);
             }
             catch (InterruptedException e) {
                 System.out.println("exception:" + e);
             }
        }

     }


     private static class QuoteBuffer {
            private Object[] keyArr;  
            private Price[] testArr;  

            public TestBuffer(int size) {
                keyArr = new Object[size];
                testArr = new Price[size];
            }

            public Price get(Object key) {
                if (key != null) {
                    for (int i=0; i<keyArr.length; i++) {
                        if ( key.equals(keyArr[i]) )
                            return quoteArr[i];
                    }
                }
                return null;
            }

            private void _slideTestQuotes() {
                Object prevKey = null;
                Price prevQuote = null;
                Object tempKey;
                Price tempQuote;
                for (int i=0; i<keyArr.length; i++) {
                    // slide key to the next index
                    tempKey = keyArr[i];
                    keyArr[i] = prevKey;
                    prevKey = tempKey;
                   // tempKey = null;  //I am guessing uncommenting this should make a difference

                    // slide quote to the next index
                    tempQuote = quoteArr[i];
                    quoteArr[i] = prevQuote;
                    prevQuote = tempQuote;
                 //   tempQuote=  null;   //I am guessing uncommenting this should make a difference
                }
            }

            public void push(Object key, Double quote) {
                _slideTestQuotes();
                keyArr[0] = key;
                quoteArr[0] = new Price(quote); //quote;
            }
     }






       public class Price {

            Double price;
            Double a1;
            Double a2;
            Double a3;
            Double a4;
            Double a5;
            Double a6;

            Price(Double price) {
                this.price = price;
                this.a1 = price;
                this.a2 = price;;
                this.a3 = price;
                this.a4 = price;
                this.a5 = price;
                this.a6 = price;
            }

        }

【问题讨论】:

  • Java 有一个 GC。您需要非常努力地解决内存泄漏,对象不必为了被收集而“无效”,它只需要不可访问。
  • 只要没有对它的引用,您就不必将对象清空。还要记住 Double != double...
  • 你有什么问题?你遇到 OutOfMemoryError 了吗?
  • 欢迎使用无需自己管理内存的 Java。不,您不需要将临时变量设置为 null,并且此代码不会导致内存泄漏。
  • 我知道 Double != double - 我只是在几分钟内写了这个来测试。我了解参考部分(这就是我在帖子中提到范围的原因)。我认为(根据我的帖子)不清空数组中的对象可能会导致对象停留更长时间,而不是在年轻代中被收集,而是被迁移到 s0/s1 甚至可能是老一代。我正在寻找的应用程序正在经历太多的旧集合(我没有等效的测试环境来测试这个,而且如果没有足够强大的案例,我无法进行产品更改)。

标签: java memory-leaks


【解决方案1】:

您不需要实际设置对 null 的引用以使其符合垃圾回收条件。考虑以下 sn-p:

Double d = new Double(1.1);  // (1)
d = new Double(2.2);         // (2)

在第 2 行,对象句柄“d”被分配了一个新值。这意味着值 1.1 的原始 Double 现在无法再以任何方式访问,并且有资格进行垃圾回收。无需先专门写“d = null”。

【讨论】:

    【解决方案2】:

    Java 垃圾收集器将收集所有不再可访问的对象。您不必取消引用;

    ref = null;
    ref = newRef;
    

    ref = newRef;
    

    具有完全相同的效果,如果没有其他对 ref 指向的对象的引用,都会导致垃圾收集器收集该对象。

    当您想丢弃对对象的引用但不为引用分配新值时,您只需要将引用清空。在这种情况下,忘记清空引用可能确实会导致内存泄漏,因为仍然存在对您可能不再需要的对象的引用。

    【讨论】:

      【解决方案3】:

      但是,当从数组中删除最旧的项目时,对象引用并没有被清空,即只有数组索引被另一个对象写入。 - 这是关键点。无论您是将引用设置为 null 还是将其设置为其他对象,如果没有更多对它的引用,“原始”对象将变得无法访问。

      例子:

      arr[0] = new myObject();
      MyObject my = arr[0];
      arr[0]=null; // or arr[0] = new myObject(); makes no difference. Since The original MyObject is still reachable, it will not be considered for GC.
      
      my=null; // or my=new MyObject() // now the original MyObject instance will be unreachable and hence ready for GC.
      

      【讨论】:

        猜你喜欢
        • 2016-02-20
        • 2018-06-26
        • 1970-01-01
        • 1970-01-01
        • 2012-10-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多