網頁

2014年3月20日 星期四

Memory Leak修復substring()

Mix經常在使用字串,也知道作字串增刪的時候,不要使用+,-等這類的運算元,而是改用StringBuffer或StringBuilder來處理字串,不過在某些狀況下,還是有可能會造成Memory Leak內存洩漏。


為了觀察GC狀況,Mix在Eclipse -> Install JREs,預設JVM參數,只加上-verbose:gc,不作任何其他的優化,針對1個大字串,長度約1M大小,使用substring()來取2個字元,重複1萬次,來進行測試。








package org.openyu.java.memoryleak;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

/**
 * The Class SubstringTest.
 */
public class SubstringLeakTest {

 /**
  * Substring.
  *
  * memory leak
  */
 @Test
 public void substring() {
  List<string> result = new ArrayList<string>(10000);
  int count = 10000;
  long beg = System.currentTimeMillis();
  for (int i = 0; i < count; i++) {
   result.add(new Substring().substring());
  }
  long end = System.currentTimeMillis();
  //
  System.out.println((end - beg) + " mills.");
 }

 /**
  * The Class Substring.
  */
 protected class Substring {

  /** The value. */
                // 1M
  private String value = new String(new byte[1 * 1024 * 1024]);

  /**
   * Substring.
   *
   * @return the string
   */
  public String substring() {
   return this.value.substring(0, 2);
  }
 }
}






Mix觀察到,內存發生了OutOfMemoryError。

conosle印出了很多[Full GC 409744K->362996K(506880K), 0.1100240 secs]的字樣,這表示內存不足,GC一直再回收,但卻比不上內存消耗的速度,程式無法執行了,就這樣直接掛掉。








這是因為用substring()取2個字元,原先的大字串,在內存是佔原本的大小並沒有縮小 ,看到的是僅是部份的內容,此大字串有被reference,所以GC無法回收。

當改用new String()傳回值,原先的大字串,就沒有被reference到 ,而GC就可以順利地回收了,修復了Memory Leak內存洩漏的情況。


package org.openyu.java.memoryleak;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

/**
 * The Class SubstringTest.
 */
public class SubstringLeakTest {

 /**
  * New string substring.
  *
  * #fix 1
  */
 @Test
 public void newStringSubstring() {
  List<string> result = new ArrayList<string>(10000);
  int count = 10000;
  long beg = System.currentTimeMillis();
  for (int i = 0; i < count; i++) {
   result.add(new NewStringSubstring().substring());
  }
  long end = System.currentTimeMillis();
  //
  System.out.println((end - beg) + " mills.");
 }

 /**
  * The Class NewStringSubstring.
  */
 protected class NewStringSubstring {

  /** The value. */
  // 1M
  private String value = new String(new byte[1 * 1024 * 1024]);

  /**
   * Substring.
   *
   * @return the string
   */
  public String substring() {
   return new String(this.value.substring(0, 2));
  }
 }
}



console查看其結果。

[GC 139307K->1051K(506880K), 0.0002765 secs]
9290 mills.






另一種修復方式,使用StringBuilder來處理,GC也可以回收了,Memory Leak內存洩漏不再發生。

package org.openyu.java.memoryleak;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

/**
 * The Class SubstringTest.
 */
public class SubstringLeakTest {

 /**
  * String builder substring.
  *
  * #fix 2
  */
 @Test
 public void stringBuilderSubstring() {
  List<String> result = new ArrayList<String>(10000);
  int count = 10000;
  long beg = System.currentTimeMillis();
  for (int i = 0; i < count; i++) {
   result.add(new StringBuilderSubstring().substring());
  }
  long end = System.currentTimeMillis();
  //
  System.out.println((end - beg) + " mills.");
 }

 /**
  * The Class StringBuilderSubstring.
  */
 protected class StringBuilderSubstring {

  /** The value. */
  // 1M
  private String value = new String(new byte[1 * 1024 * 1024]);

  /**
   * Substring.
   *
   * @return the string
   */
  public String substring() {
   StringBuilder buff = new StringBuilder();
   buff.append(value);
   return buff.substring(0, 2);
  }
 }
}



console查看其結果。

[GC 139301K->1051K(506880K), 0.0002325 secs]
16195 mills.



沒有留言:

張貼留言

Related Posts Plugin for WordPress, Blogger...