2011-11-17 8 views
8

Ứng dụng của tôi cần nhiều bộ nhớ và cấu trúc dữ liệu lớn để thực hiện công việc của nó. Thường thì ứng dụng cần nhiều hơn 1 GB bộ nhớ, và trong một số trường hợp, khách hàng của tôi thực sự cần phải sử dụng phiên bản 64-bit của ứng dụng vì chúng có vài gigabyte bộ nhớ.Bắt buộc Windows tải DLL ở những nơi để bộ nhớ bị phân mảnh tối thiểu

Trong quá khứ, tôi có thể dễ dàng giải thích cho người dùng rằng nếu bộ nhớ đạt 1,6 đến 1,7 GB dung lượng bộ nhớ, nó đã hết bộ nhớ hoặc gần với tình trạng 'hết bộ nhớ' và họ cần để giảm bộ nhớ hoặc chuyển sang phiên bản 64 bit.

Năm cuối cùng tôi nhận thấy rằng ứng dụng thường chỉ sử dụng khoảng 1 GB trước khi hết bộ nhớ. Sau khi một số điều tra có vẻ như nguyên nhân của vấn đề này là phân mảnh bộ nhớ. Tôi đã sử dụng VMMAP (một tiện ích SysInternals) để xem xét việc sử dụng bộ nhớ của ứng dụng của tôi và thấy một cái gì đó như thế này: Address Space Fragmentation

Khu vực màu cam là bộ nhớ được cấp bởi ứng dụng của tôi. Các vùng màu tím là mã thực thi.

Như bạn có thể thấy ở nửa dưới của hình ảnh, các khu vực màu tím (là của DLL) được tải tại nhiều địa chỉ khác nhau, khiến bộ nhớ của tôi bị phân mảnh. Điều này không thực sự là vấn đề nếu khách hàng của tôi không có nhiều dữ liệu, nhưng nếu khách hàng của tôi có bộ dữ liệu chiếm hơn 1 GB và một phần của ứng dụng cần một khối bộ nhớ lớn (ví dụ: 50 MB), nó có thể dẫn đến lỗi phân bổ bộ nhớ, khiến ứng dụng của tôi bị lỗi.

Hầu hết cấu trúc dữ liệu của tôi dựa trên STL và thường không đòi hỏi nhiều bộ nhớ tiếp giáp, nhưng trong một số trường hợp (ví dụ: các chuỗi rất lớn), nó thực sự cần thiết để có một khối bộ nhớ liền kề. Thật không may, nó không phải là luôn luôn có thể thay đổi mã để nó không cần một khối bộ nhớ liền kề như vậy.

Các câu hỏi là:

  • Làm thế nào tôi có thể ảnh hưởng đến vị trí nơi DLL được nạp trong bộ nhớ, mà không sử dụng một cách rõ ràng rebase trên tất cả các của DLL trên máy tính của khách hàng, hoặc không tải tất cả của DLL một cách rõ ràng.
  • Có cách nào để chỉ định địa chỉ tải của tệp DLL trong tệp kê khai ứng dụng của riêng bạn không?
  • Hoặc có cách nào để thông báo cho Windows (thông qua tệp kê khai không?) Để không phân tán tệp DLL xung quanh (tôi nghĩ rằng sự tán xạ này được gọi là ASLR).

Tất nhiên, giải pháp tốt nhất là giải pháp mà tôi có thể ảnh hưởng từ tệp kê khai của ứng dụng vì tôi dựa vào tải tự động/động của DLL của Windows.

Ứng dụng của tôi là ứng dụng hỗn hợp (được quản lý + không được quản lý), mặc dù phần chính của ứng dụng không được quản lý.

Bất kỳ đề xuất nào?

+0

Đây có phải là thứ có thể giúp bạn không? http://msdn.microsoft.com/en-us/library/f7f5138s.aspx – detunized

+1

mmm, bạn có thực sự cần nhiều bộ nhớ cùng một lúc không? Process Monitor lưu trữ nhật ký của nó trong bộ nhớ ảo và chỉ đưa dữ liệu vào không gian địa chỉ bộ nhớ của quá trình khi cần, kiểm tra http://blogs.msdn.com/b/oldnewthing/archive/2004/08/10/211890.aspx để biết mã Ví dụ –

+1

Tôi không chắc mọi người để lại một câu trả lời hiểu được các nhánh của ASLR: http://en.wikipedia.org/wiki/ASLR –

Trả lời

5

Đầu tiên, phân mảnh không gian địa chỉ ảo của bạn không nhất thiết phải gây ra tình trạng hết bộ nhớ. Đây là trường hợp nếu ứng dụng của bạn phải phân bổ khối liên tiếp khối bộ nhớ có kích thước phù hợp. Nếu không thì tác động của sự phân mảnh nên nhỏ.

Bạn nói hầu hết dữ liệu của mình là "dựa trên STL", nhưng nếu ví dụ bạn phân bổ một số lớn std::vector, bạn sẽ cần khối bộ nhớ liền kề.

AFAIK không có cách nào để chỉ định địa chỉ ánh xạ ưa thích của DLL khi tải. Vì vậy, chỉ có hai lựa chọn: hoặc rebase nó (file DLL), hoặc thực hiện DLL tải mình (mà không phải là tầm thường của khóa học).

Thông thường bạn không cần phải rebase các API Windows API chuẩn, chúng được tải tại không gian địa chỉ của bạn rất chặt chẽ. Phân mảnh có thể đến từ một số DLL bên thứ ba (chẳng hạn như cửa sổ móc, chống vi-rút và vv)

3

Bạn không thể thực hiện việc này với tệp kê khai, nó phải được thực hiện bằng tùy chọn liên kết/BASE. Linker + Advanced + Base address trong IDE. Cách linh hoạt nhất là sử dụng tên/BASE: @ filename, cú pháp khóa sao cho trình liên kết đọc địa chỉ cơ sở từ một tệp văn bản.

Cách tốt nhất để tải tệp văn bản là từ cửa sổ Mô-đun + Windows + Mô-đun. Nhận bản phát hành Bản phát hành của chương trình được tải trong trình gỡ rối và tải toàn bộ shebang. Debug + Break All, mở cửa sổ lên và copy nó vào file văn bản. Chỉnh sửa nó để phù hợp với định dạng được yêu cầu, tính toán các địa chỉ tải từ cột Địa chỉ. Để lại đủ không gian giữa các tệp DLL để bạn không phải liên tục chỉnh sửa tệp văn bản.

+0

Tất nhiên điều này không giúp ích gì với tất cả các DLL hook tìm thấy trên một hệ thống điển hình . Trình điều khiển đồ họa. Chống vi-rút. Trình điều khiển chuột. Vv –

+0

Hmm, không, ngay cả những người có thể bị tấn công bằng công cụ rebase.exe. Không chắc chắn như vậy tôi muốn khuyên bạn nên làm điều này, lãng phí thời gian, trừ khi bạn có kế hoạch vận chuyển máy của bạn với sản phẩm của bạn. –

1

Nếu bạn có thể thực thi một số mã của riêng bạn trước khi các thư viện được đề cập được tải, bạn có thể đặt trước cho mình một khoảng không gian địa chỉ lớn đẹp đẽ để phân bổ.

Nếu không, bạn cần phải xác định các DLL chịu trách nhiệm, để xác định lý do tại sao chúng đang được tải. Ví dụ, chúng là một phần của .NET, thư viện runtime của ngôn ngữ, mã của riêng bạn, hoặc các thư viện của bên thứ ba mà bạn đang sử dụng?

Đối với mã của riêng bạn, giải pháp hợp lý nhất có lẽ là sử dụng tĩnh thay vì liên kết động. Điều này cũng có thể cho thời gian chạy ngôn ngữ và có thể có cho thư viện của bên thứ ba.

Đối với thư viện của bên thứ ba, bạn có thể thay đổi bằng cách sử dụng tải ngầm để tải rõ ràng, do đó việc tải chỉ diễn ra sau khi bạn đã đặt trước không gian địa chỉ của mình.

Tôi không biết liệu bạn có thể làm gì với các thư viện .NET không; nhưng vì hầu hết mã của bạn không được quản lý, có thể loại bỏ các thành phần được quản lý để loại bỏ .NET. Hoặc có lẽ bạn có thể chia các phần .NET thành một quá trình riêng biệt.

+0

... nhưng nó sẽ là hợp lý hơn để tái cấu trúc chương trình khi cần thiết để loại bỏ yêu cầu đối với khối bộ nhớ tiếp giáp lớn. –