2017-04-10 148 views
2

等待很長一段時間我的代碼執行和它的指向我這個方法GC開銷超出限制 - 陣列

public Iterable<Board> neighbors() { 
     Queue<Board> q = new LinkedList<>(); 
     int n = dimension(); 
     int x = 0, y = 0; 
     outer: 
     // do some stuff to get the x and y 
     if (y+1 < n) { 
      the line where i get the error -> int [][]arr = new int[n][n]; 
      for (int i = 0; i < tiles.length; i++) { 
       arr[i] = Arrays.copyOf(tiles[i], n); 
      } 
      // do some stuff 
      Board br = new Board(arr); 
      if(!this.equals(br)) { 
       q.add(new Board(arr)); 
      } 
     } 
     if (y-1 >= 0) { 
      int [][]arr = new int[n][n]; 
      for (int i = 0; i < tiles.length; i++) { 
       arr[i] = Arrays.copyOf(tiles[i], n); 
      } 
      // do some stuff 
      Board br = new Board(arr); 
      if(!this.equals(br)) { 
       q.add(new Board(arr)); 
      } 
     } 
     if (x-1 >= 0) { 
      int [][]arr = new int[n][n]; 
      for (int i = 0; i < tiles.length; i++) { 
       arr[i] = Arrays.copyOf(tiles[i], n); 
      } 
      // do some stuff 
      Board br = new Board(arr); 
      if(!this.equals(br)) { 
       q.add(new Board(arr)); 
      } 
     } 
     if (x+1 < n) { 
      int [][]arr = new int[n][n]; 
      for (int i = 0; i < tiles.length; i++) { 
       arr[i] = Arrays.copyOf(tiles[i], n); 
      } 
      // do some stuff 
      Board br = new Board(arr); 
      if(!this.equals(br)) { 
       q.add(new Board(arr)); 
      } 
     } 
     return q; 
    } 

基本上,我需要複製磚陣列和更改副本後,我得到這個錯誤「 ARR「,但保持瓷磚陣列不改變使用它以後..我真的不喜歡我做的方式複製和粘貼代碼我認爲它效率低下,但沒有其他方式來到我的腦海中,所以我想要知道爲什麼我得到這個錯誤「我知道它是因爲GC需要更多的時間而不做很多」,但我想知道爲什麼它發生在這種情況下,如果有更好的方法來複制數組。 也我增加了堆內存-Xmx1600m

感謝您的時間。

+0

在這種情況下'n'有多大? – Compass

+0

通過'new int [n] []'而不是'new int [n] [n]'初始化'arr',可以安全地完成一些GC工作。 – Socowi

+0

@Compass n是3 –

回答

1

的問題

很可能這個問題在時間短時間內創造大量的對象出現。有關更多信息,請參見this answer

目前,一個Board至少由四個對象的:

  • 板本身
  • 基板內部的陣列arr
  • 內部arr

創建的三個陣列更少物體

我們走al是創建更少的對象(數組)。既然你只想處理小板,我們可以使用一個long來存儲完整的3×3板。 A long具有64位。我們使用每場64/9 = 7位來存儲該字段的值:

state = ... 0000100 0000011 0000010 0000001 0000000 
      4th field ↑ 2nd field ↑ 0th field 
        3rd field  1st field 

以下類處理位操作。

class Board { 

    private final static int SIDE_LENGTH = 3; 
    private final static int FIELDS = SIDE_LENGTH * SIDE_LENGTH; 
    private final static int BITS_PER_FIELD = 64/FIELDS; 
    private final static long FIELD_MASK = (1 << BITS_PER_FIELD) - 1; 

    private long state; 

    public Board() { 
     for (int field = 0; field < FIELDS; ++field) { 
      set(field, field); 
     } 
    } 

    /** Copy constructor. */ 
    public Board(Board other) { 
     this.state = other.state; 
    } 

    public int get(int x, int y) { 
     return get(coordinatesToField(x, y)); 
    } 

    public void set(int x, int y, int value) { 
     set(coordinatesToField(x, y), value); 
    } 

    private int coordinatesToField(int x, int y) { 
     return SIDE_LENGTH * y + x; 
    } 

    private int get(int field) { 
     return (int) ((state >>> (field * BITS_PER_FIELD)) & FIELD_MASK); 
    } 

    private void set(int field, int value) { 
     int shift = field * BITS_PER_FIELD; 
     state &= ~(FIELD_MASK << shift); 
     state |= (long) value << shift; 
    } 

    public String toString() { 
     StringBuilder sb = new StringBuilder(); 
     for (int field = 0; field < FIELDS; ++field) { 
      sb.append(get(field)); 
      sb.append((field + 1) % SIDE_LENGTH == 0 ? "\n" : "\t"); 
     } 
     return sb.toString(); 
    } 

    // TODO implement equals and hashCode 
} 

當使用這個類,你不必再處理陣列,這不僅節省了大量的對象,而且在你的prorgram複製代碼。

該類還適用於1×1,2×2和4×4板,但由於64位限制,該類不適用於較大的板。

用法示例

public static void main(String[] args) { 
    // Create and print the initial board 
    // 0 1 2 
    // 3 4 5 
    // 6 7 8 
    Board b = new Board(); 
    System.out.println(b); 

    // Copy an existing board 
    Bord copy = new Board(b); 

    // Set the upper right field to value 8 
    copy.set(2, 0, 8); 

    // Print the center field 
    // 4 
    Syste.out.println(copy.get(1, 1)); 

} 

更多的想法

你甚至可以避免創建Board對象所有,並且只存儲long值。但是,當您使用泛型(例如LinkedList)時,由於Java的自動裝箱功能,這並沒有幫助。

另請注意,LinkedList將每個條目包裝在其他節點對象中。也許你可以像循環緩衝區一樣使用更高效的DataStructure。

根據你在做什麼,你不妨看看Flyweight design pattern

相關問題