Như bạn có thể đã tìm ra, vấn đề là bạn đang cố gắng cấp phát một khối bộ nhớ lớn liền kề, khối này không hoạt động do phân mảnh bộ nhớ. Nếu tôi cần làm những gì bạn đang làm, tôi sẽ làm như sau:
int sizeA = 10000,
sizeB = 10000;
double sizeInMegabytes = (sizeA * sizeB * 8.0) / 1024.0 / 1024.0; //762 mb
double[][] randomNumbers = new double[sizeA][];
for (int i = 0; i < randomNumbers.Length; i++)
{
randomNumbers[i] = new double[sizeB];
}
Sau đó, để có được một chỉ mục cụ thể mà bạn sẽ sử dụng randomNumbers[i / sizeB][i % sizeB]
.
Một tùy chọn khác nếu bạn luôn truy cập các giá trị theo thứ tự có thể là sử dụng hàm tạo đã được nạp chồng để chỉ định hạt giống. Bằng cách này, bạn sẽ nhận được một số bán ngẫu nhiên (như DateTime.Now.Ticks
) lưu trữ nó trong một biến, sau đó khi bạn bắt đầu xem qua danh sách, bạn sẽ tạo một phiên bản Ngẫu nhiên mới bằng cách sử dụng hạt giống ban đầu:
private static int randSeed = (int)DateTime.Now.Ticks; //Must stay the same unless you want to get different random numbers.
private static Random GetNewRandomIterator()
{
return new Random(randSeed);
}
Điều quan trọng cần lưu ý là mặc dù blog được liên kết trong câu trả lời của Fredrik Mörk chỉ ra rằng vấn đề thường là do thiếu không gian địa chỉ, nó không liệt kê một số vấn đề khác, như giới hạn kích thước đối tượng 2GB CLR (được đề cập trong nhận xét từ ShuggyCoUk trên cùng một blog), đề cập đến sự phân mảnh bộ nhớ và không đề cập đến tác động của kích thước tệp trang (và cách giải quyết vấn đề này bằng cách sử dụng CreateFileMapping
hàm ).
Giới hạn 2GB có nghĩa là randomNumbers
phải nhỏ hơn 2GB. Vì mảng là các lớp và có một số chi phí là bản thân của chúng, điều này có nghĩa là một mảng double
sẽ cần phải nhỏ hơn 2 ^ 31. Tôi không chắc chiều dài sẽ phải nhỏ hơn bao nhiêu thì 2 ^ 31, nhưng Chi phí của một mảng .NET? cho biết 12 - 16 byte.
Phân mảnh bộ nhớ rất giống với phân mảnh ổ cứng. Bạn có thể có 2GB không gian địa chỉ, nhưng khi bạn tạo và hủy các đối tượng, sẽ có khoảng cách giữa các giá trị. Nếu những khoảng trống này quá nhỏ so với đối tượng lớn của bạn và không thể yêu cầu thêm không gian, thì bạn sẽ nhận đượcSystem.OutOfMemoryException
. Ví dụ: nếu bạn tạo đối tượng 2 triệu, 1024 byte, thì bạn đang sử dụng 1,9GB. Nếu bạn xóa mọi đối tượng mà địa chỉ không phải là bội số của 3 thì bạn sẽ sử dụng bộ nhớ .6GB, nhưng nó sẽ được trải rộng trên không gian địa chỉ với các khối mở 2024 byte ở giữa. Nếu bạn cần tạo một đối tượng có dung lượng .2GB, bạn sẽ không thể thực hiện được vì không có khối đủ lớn để chứa nó và không thể lấy thêm không gian (giả sử là môi trường 32 bit). Các giải pháp khả thi cho vấn đề này là những thứ như sử dụng các đối tượng nhỏ hơn, giảm lượng dữ liệu bạn lưu trữ trong bộ nhớ hoặc sử dụng thuật toán quản lý bộ nhớ để hạn chế / ngăn phân mảnh bộ nhớ. Cần lưu ý rằng trừ khi bạn đang phát triển một chương trình lớn sử dụng một lượng lớn bộ nhớ thì điều này sẽ không thành vấn đề. Cũng thế,
Vì hầu hết các chương trình yêu cầu bộ nhớ hoạt động từ HĐH và không yêu cầu ánh xạ tệp, chúng sẽ bị giới hạn bởi RAM của hệ thống và kích thước tệp trang. Như đã lưu ý trong nhận xét của Néstor Sánchez (Néstor Sánchez) trên blog, với mã được quản lý như C #, bạn bị mắc kẹt với giới hạn tệp RAM / trang và không gian địa chỉ của hệ điều hành.
Đó là cách lâu hơn dự kiến. Hy vọng rằng nó sẽ giúp một ai đó. Tôi đã đăng nó vì tôi đã System.OutOfMemoryException
chạy chương trình x64 trên hệ thống có RAM 24GB mặc dù mảng của tôi chỉ chứa 2GB nội dung.