2010-01-27 27 views
6

Tôi có một tệp mà từ đó tôi đọc dữ liệu. Tất cả các văn bản từ tập tin này được lưu trữ trong một biến String (một biến rất lớn). Sau đó, trong một phần khác của ứng dụng của tôi, tôi muốn đi qua chuỗi này và trích xuất thông tin hữu ích, từng bước (phân tích cú pháp chuỗi).Cách xử lý các chuỗi lớn và bộ nhớ hạn chế

Trong khi đó bộ nhớ của tôi bị đầy và ngoại lệ OutOfMemory ngăn tôi xử lý tiếp. Tôi nghĩ sẽ tốt hơn khi xử lý dữ liệu trực tiếp trong khi đọc đầu vào từ tệp. Nhưng đối với mục tiêu tổ chức, tôi muốn chuyển Chuỗi cho một phần khác trong đơn đăng ký của tôi.

Tôi nên làm gì để giữ cho bộ nhớ không bị tràn?

+0

Bạn không thể phân tích cú pháp tệp từng chút một với một trong các Trình đọc (ví dụ: BufferedReader)? –

Trả lời

7

Bạn nên sử dụng BufferedInputReader thay vì lưu trữ tất cả thành một chuỗi lớn.

Nếu những gì bạn muốn phân tích xảy ra trên cùng một dòng, thì StringTokenizer sẽ hoạt động khá độc đáo, bạn phải nghĩ ra cách đọc những gì bạn muốn từ tệp để phân tích cú pháp, sau đó áp dụng StringTokenizer tuyên bố.

+0

+1. Anthony: ý tưởng chung là bạn vượt qua CURSORS (như trong DB). Chúng có thể là Người đọc trong trường hợp văn bản, Luồng trong trường hợp byte, trình lặp trong trường hợp chuỗi các mục hoặc bất kỳ thứ gì. Bạn có thể chuyển đổi một loại thành một loại khác (chuyển đổi từng mục của chuỗi, ví dụ, một dòng trong tệp thành đối tượng miền) nhưng một phần của ứng dụng đang cung cấp cho một loại khác là con trỏ, do đó, đó là một xử lý để tiêu thụ đầu vào một bước tại một thời điểm mà không phải chịu đựng trong kiến ​​thức của các tập tin đọc hoặc bất kỳ chuyển đổi nào bạn thực hiện ở giữa. – helios

+0

Các liên kết bạn cung cấp 'BufferedInputReader' và' StringTokenizer' không có sẵn. – Root

6

Nếu bạn có thể nới lỏng các yêu cầu của mình một chút, bạn có thể triển khai java.lang.CharSequence được hỗ trợ bởi tệp của bạn.

CharSequence được hỗ trợ many places in the JDK (Chuỗi là một CharSequence). Vì vậy, đây là một lựa chọn tốt cho việc thực hiện dựa trên Reader.

1

Bạn phải xem lại thuật toán của mình để xử lý dữ liệu lớn. Bạn phải xử lý chunk-by-chank dữ liệu này hoặc sử dụng truy cập tệp ngẫu nhiên mà không lưu trữ dữ liệu trong bộ nhớ. Ví dụ: bạn có thể sử dụng StringTokenizer hoặc StreamTokenizer như đã nói @Zombies. Bạn có thể xem các kỹ thuật phân tích cú pháp-lexer: khi trình phân tích cú pháp phân tích một số biểu thức nó yêu cầu lexer đọc lexem tiếp theo (mã thông báo), nhưng không đọc toàn bộ luồng đầu vào cùng một lúc.

4

Những người khác đã đề xuất đọc và xử lý các phần của tệp của bạn cùng một lúc. Nếu có thể, một trong những cách đó sẽ tốt hơn.

Tuy nhiên, nếu điều này là không thể và bạn có thể nạp String ban đầu vào bộ nhớ như bạn chỉ ra nhưng sau đó phân tích cú pháp chuỗi này gây ra sự cố, bạn có thể sử dụng chất nền. Trong Java một chuỗi con bản đồ trên đầu trang của bản gốc char mảng và chỉ mất bộ nhớ cho các cơ sở Object và sau đó bắt đầu và chiều dài int con trỏ.

Vì vậy, khi bạn tìm thấy một phần của chuỗi mà bạn muốn giữ riêng biệt, sử dụng một cái gì đó như:

String piece = largeString.substring(foundStart, foundEnd); 

Nếu bạn thay này hoặc mã mà trong nội bộ thực hiện điều này, thì việc sử dụng bộ nhớ sẽ tăng lên đáng kể :

new String(largeString.substring(foundStart, foundEnd)); 

Lưu ý rằng bạn phải sử dụng String.substring() vì lý do chính vì lý do này. Bạn có thể có một chuỗi rất lớn, trong đó bạn lấy một chuỗi con và sau đó loại bỏ tham chiếu của bạn thành chuỗi gốc. Vấn đề là chuỗi con vẫn tham chiếu đến mảng char lớn ban đầu. GC sẽ không phát hành cho đến khi chuỗi con cũng bị xóa. Trong trường hợp như thế này, sẽ hữu ích khi sử dụng new String(...) để đảm bảo mảng lớn không sử dụng sẽ bị GC loại bỏ (đây là một trong số ít trường hợp bạn nên sử dụng new String(...)).

Kỹ thuật khác, nếu bạn mong đợi có nhiều chuỗi nhỏ và có thể có cùng giá trị, nhưng đến từ nguồn bên ngoài (như tệp), hãy sử dụng .intern() sau khi tạo chuỗi mới.

Lưu ý: Điều này phụ thuộc vào việc thực hiện String mà bạn thực sự không cần phải biết, nhưng trong thực tế cho các ứng dụng lớn đôi khi bạn phải dựa vào kiến ​​thức đó. Hãy lưu ý rằng các phiên bản Java trong tương lai có thể thay đổi điều này (mặc dù không có khả năng).

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