2015-01-21 21 views
9

Tôi tò mò - đôi khi tôi thực hiện các thay đổi trong mã, biên dịch lại, sau đó sao chép tệp exe hoặc dll của tôi qua phiên bản cũ và thấy Windows cho biết ngày của tệp đã thay đổi, nhưng kích thước vẫn giữ nguyên. Tại sao vậy?Tại sao những thay đổi nhỏ trong mã không ảnh hưởng đến kích thước tệp exe?

Như một ví dụ, tôi đã thử nghiệm với các ứng dụng giao diện điều khiển sau:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication4 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int a = 1; 
      int b = 2; 
      Console.WriteLine(a + b); 
     } 
    } 
} 

này tạo ra một tập tin exe của 5120 byte (Visual Studio 2012, Debug xây dựng). Sau đó, tôi đã thay đổi mã này:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication4 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int a = 1; 
      int b = 2; 
      int c = 3; 
      Console.WriteLine(a + b + c); 
     } 
    } 
} 

Kích thước của exe hoàn toàn giống nhau.

tôi nhìn vào tháo dỡ, được thể hiện một sự khác biệt trong các mã IL, vì vậy nó không thể là rằng sự khác biệt được tối ưu hóa đi:

Đầu tiên phiên bản:

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  15 (0xf) 
    .maxstack 2 
    .locals init (int32 V_0, 
      int32 V_1) 
    IL_0000: nop 
    IL_0001: ldc.i4.1 
    IL_0002: stloc.0 
    IL_0003: ldc.i4.2 
    IL_0004: stloc.1 
    IL_0005: ldloc.0 
    IL_0006: ldloc.1 
    IL_0007: add 
    IL_0008: call  void [mscorlib]System.Console::WriteLine(int32) 
    IL_000d: nop 
    IL_000e: ret 
} // end of method Program::Main 

phiên bản thứ hai:

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  19 (0x13) 
    .maxstack 2 
    .locals init ([0] int32 a, 
      [1] int32 b, 
      [2] int32 c) 
    IL_0000: nop 
    IL_0001: ldc.i4.1 
    IL_0002: stloc.0 
    IL_0003: ldc.i4.2 
    IL_0004: stloc.1 
    IL_0005: ldc.i4.3 
    IL_0006: stloc.2 
    IL_0007: ldloc.0 
    IL_0008: ldloc.1 
    IL_0009: add 
    IL_000a: ldloc.2 
    IL_000b: add 
    IL_000c: call  void [mscorlib]System.Console::WriteLine(int32) 
    IL_0011: nop 
    IL_0012: ret 
} // end of method Program::Main 

Nếu mã lớn hơn về mặt thể chất, thì các tệp có kích thước chính xác như thế nào? Đây có phải là một cơ hội ngẫu nhiên không? Điều đó xảy ra với tôi rất nhiều (khi thực hiện các thay đổi nhỏ đối với mã) ...

+2

Trong một từ: căn chỉnh. – Fizz

+0

5120 chính xác là 10 ngành. Hình như một số đệm. Có lẽ cũng liên kết (nếu mã thực tế được theo sau bởi cái gì khác mà nên được liên kết theo ngành). – morfizm

Trả lời

6

Từ https://msdn.microsoft.com/en-us/library/ms809762.aspx:

DWORD FileAlignment

Trong tập tin PE, dữ liệu thô mà bao gồm mỗi phần được đảm bảo để bắt đầu tại một bội số của giá trị này. Giá trị mặc định là 0x200 byte, có lẽ để đảm bảo rằng các phần luôn bắt đầu ở phần đầu của một sector đĩa (cũng có độ dài 0x200 byte). Trường này tương đương với kích thước liên kết phân đoạn/tài nguyên trong các tệp NE. Không giống như các tệp NE, các tệp PE thường không có hàng trăm phần, do đó không gian lãng phí bằng cách căn chỉnh các phần của tệp hầu như luôn luôn rất nhỏ.

EDIT: Ngoài ra tất cả các kích thước của phần trên đĩa được làm tròn (được đệm) thành bội số của FileAlignment. Từ http://www.openwatcom.org/ftp/devel/docs/pecoff.pdf

SizeOfRawData

Kích thước của phần (đối tượng tập tin) hoặc kích thước của dữ liệu khởi tạo trên đĩa (file ảnh). Đối với hình ảnh thực thi , đây phải là bội số của FileAlignment từ tiêu đề tùy chọn. Nếu điều này nhỏ hơn VirtualSize phần còn lại của phần không được lấp đầy. Vì trường này được làm tròn trong khi trường VirtualSize không phải là , điều này có thể lớn hơn VirtualSize là . Khi một phần chỉ chứa dữ liệu chưa được khởi tạo, trường này phải là 0.

Tôi đoán rằng ngay cả những phần cuối cùng là để đệm để mã mối liên kết mà phát ra phần và sau đó mã loader đó tải chúng không cần phải lo lắng về một trường hợp đặc biệt đối với kích thước phần ngoái. Nó sẽ là một sự tối ưu hóa vô nghĩa để cắt phần cuối bằng cách nào đó vì khu vực đĩa (và trên đỉnh của cụm lớn hơn của hệ thống tập tin) có internal fragmentation sẽ ăn lại bất kỳ "tiết kiệm" như vậy (từ cắt tỉa phần cuối cùng) phần lớn thời gian .

+0

Thú vị, tôi không biết điều đó. Điều đó chắc chắn giải thích nó. – vesan

5

Tệp thực thi có chứa một số phần. Mỗi phần trong số này được căn chỉnh, nếu tôi nhớ chính xác, 512 byte.

+0

Có vẻ như bạn nói đúng, điều đó có nghĩa là tệp của tôi là 10 phần theo 512 byte = 5120. – vesan

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