2011-12-21 28 views
20

Các chuyên gia Java nhấn mạnh tầm quan trọng của việc tránh tối ưu hóa sớm và tập trung thay vào thiết kế OO sạch. Tôi đang cố gắng hòa giải nguyên tắc này trong bối cảnh viết lại một chương trình sử dụng một mảng lớn các phần tử dài (một vài triệu). Dường như việc sử dụng một ArrayList sẽ tiêu thụ khoảng 3x bộ nhớ của một mảng nguyên thủy của thời gian dài, và lãng phí nhiều RAM dường như là một mối quan tâm hợp pháp đối với tôi.Danh sách <Double> sử dụng RAM gấp đôi []?

Tôi đang dựa vào thử nghiệm này tôi đã sử dụng lớp MemoryTestBench described here. thử nghiệm và đầu ra của tôi là như sau:

package memory; 

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

public class ArrayListExperiment { 

public static void main(String[] args) { 

    ObjectFactory arrayList = new ObjectFactory() { 
     public Object makeObject() { 
      List<Long> temp = new ArrayList<Long>(1000); 
      for (long i=0; i<1000; i++) 
       temp.add(i); 
      return temp; 
     } 
    }; 

    ObjectFactory primitiveArray = new ObjectFactory() { 
     public Object makeObject() { 
      long[] temp = new long[1000]; 
      for (int i=0; i<1000; i++) 
       temp[i] = i; 
      return temp; 
     } 
    }; 

    MemoryTestBench memoryTester = new MemoryTestBench(); 
    memoryTester.showMemoryUsage(primitiveArray); 
    memoryTester.showMemoryUsage(arrayList); 
} 
} 

và đầu ra:

memory.ArrayListExperiment$2 produced [J which took 8016 bytes 
memory.ArrayListExperiment$1 produced java.util.ArrayList which took 24968 bytes 

Câu hỏi của tôi là: Làm thế nào tôi có thể gặt hái những lợi ích của một danh sách OO và vẫn giữ lại bộ nhớ nhỏ của một mảng nguyên thủy ? Tôi nghĩ rằng ổi có thể cung cấp câu trả lời, nhưng liếc qua API nó không rõ ràng với tôi mà lớp học để sử dụng thay cho ArrayList.

Cảm ơn mọi đề xuất.

+0

Đây có phải là MemoryTestBranch đúng không? Tôi đã nhanh chóng đi qua bài báo và thấy một số cách tiếp cận thú vị như System.gc() cái khác cho một vài lần. – rit

+4

Thực ra, điều này nghe có vẻ đúng. Một Double chi phí một tham chiếu, cộng với double nguyên thủy thực tế. Ở mức tối thiểu trong một JVM 64 bit, bạn sẽ trả gấp đôi chi phí cho Double so với bạn sẽ tăng gấp đôi, và có một số chi phí bổ sung. – rfeak

+1

rit, Tôi không đủ điều kiện để nhận xét về sự sạch sẽ của phương pháp trong bài viết đó, nhưng tôi tin rằng kết quả bộ nhớ là chính xác – Jonah

Trả lời

11

Bạn có thể xem xét sử dụng Trove, cung cấp hỗ trợ cho các bộ sưu tập nguyên thủy, ví dụ lớp TDoubleArrayList:

Một thay đổi kích thước, mảng hậu thuẫn danh sách nguyên thủy kép.

Edit: Đúng là lớp này không thực hiện List, nhưng đó là giá để tránh nguyên thủy đóng hộp của Java. Guava's solution là linh hoạt nhất, trong khi Trove là tốt nhất cho các yêu cầu hiệu suất cực đoan hơn.

+1

chiến thắng trove. Việc sử dụng RAM giống như dung lượng của ổi, nhưng khả năng truy cập bộ nhớ của trove nhanh gấp hai lần, giống như nguyên thủy: http://pastebin.com/Xyd6MbEq – Jonah

+3

...Mặt khác, nó không thực hiện giao diện 'List';) – Xaerxess

3

Viết thực hiện của riêng bạn của ArrayList sử dụng một mảng nguyên thủy. Sao chép mã ArrayList hiện tại và thay thế Object [] bên trong bằng một dấu [].

Nên là một bản sao khá thẳng và thay thế.

EDIT: Nguy cơ lớn nhất đối với mức tiêu thụ bộ nhớ sẽ là "tăng trưởng". Nó sẽ mất ít nhất hai lần không gian, cộng với phòng bổ sung bạn phát triển. Nếu bạn không thể định cỡ trước mảng để tránh điều này, bạn có thể muốn xem xét việc triển khai hơi khác nhau sử dụng nhiều mảng khi nó phát triển theo thời gian. Nhiều hơn một chút toán học về chèn và lập chỉ mục, nhưng không nên tooooo xấu.

1

Arrays.asList(T...) có thể là những gì bạn đang tìm kiếm. Nó trả về một thể hiện của List<T> được hỗ trợ bởi mảng được truyền cho nó.

+4

Anh ta vẫn phải trả chi phí ban đầu để tạo ra Double [], mà anh ta muốn tránh. – rfeak

+0

Hãy nhớ rằng Danh sách kết quả sẽ có kích thước cố định, vì vậy bạn sẽ không thể gọi 'add()' trên nó mà không có lỗi. Nếu bạn muốn có thể thêm vào danh sách thì bạn sẽ cần một 'ArrayList' thông thường, với chi phí bộ nhớ cần thiết. –

+0

Jason, kích thước danh sách là cố định và được biết trước cho vấn đề cụ thể của tôi, fwiw – Jonah

5

Tôi nghĩ bạn đang tìm kiếm FastUtil'sDoubleArrayList - nó được hỗ trợ bởi một mảng nguyên thủy.

Nếu bộ sưu tập của bạn là thực sự lớn (lớn hơn 2^31 yếu tố), bạn cũng có thể muốn nhìn vào BigArrays

1

Đó là một câu hỏi hay của họ - hiệu suất vs mã sạch sẽ. Tôi nghĩ rằng bạn có căn cứ để ít quan tâm đến thiết kế OO sạch và chỉ đơn giản là tập trung vào việc tạo ra một giải pháp tốt cho vấn đề cụ thể của làm việc với một mảng lớn của thời gian dài. Nếu bạn làm như vậy, việc giữ mã định hướng hiệu suất trong một lớp/gói sẽ giảm thiểu tác động của nó lên thiết kế tổng thể. Giả sử quản lý danh sách dài các thời gian dài chỉ là một phần nhỏ của một ứng dụng lớn hơn ...

16

Tôi nghĩ rằng những gì bạn đang tìm kiếm trong ổi là Doubles.asList

+1

Phát biểu như một nhà phát triển Guava, đây thực sự là cách để làm mọi thứ, đặc biệt kể từ khi bạn đề cập đến, kích thước danh sách của bạn đã được sửa. –

+0

@LouisWasserman: Phiên bản Guava có cung cấp bất kỳ thứ gì 'Arrays.asList' không? –

+7

@TimothyJones: 'Arrays.asList' không hoạt động cho các mảng nguyên thủy ... chuyển vào một' double [] 'và bạn nhận được một phần tử duy nhất' List '. – ColinD

Các vấn đề liên quan