簡體   English   中英

為什么代碼中的小變化不會影響exe文件的大小?

[英]Why don't small changes in code affect exe file size?

我很好奇 - 有時我會在代碼中進行更改,重新編譯,然后將我的exe或dll文件復制到舊版本上,然后看到Windows告訴我文件的日期發生了變化,但是大小保持不變。 這是為什么?

作為示例,我使用以下控制台應用程序進行了測試:

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);
        }
    }
}

這產生了一個5120字節的exe文件(Visual Studio 2012,Debug build)。 然后,我將代碼更改為:

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);
        }
    }
}

exe的大小完全相同。

我看一下反匯編,它顯示了IL代碼的差異,因此不能將差異優化掉:

第一版:

.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

第二版:

.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

如果代碼在物理上更大,那么文件的大小如何完全相同? 這只是一些隨機的機會嗎? 它發生在我身上很多(當對代碼進行小的更改時)......

來自https://msdn.microsoft.com/en-us/library/ms809762.aspx

DWORD FileAlignment

在PE文件中,保證包含每個部分的原始數據以此值的倍數開始。 默認值為0x200字節,可能是為了確保節始終始於磁盤扇區的開頭(長度也為0x200字節)。 此字段等效於NE文件中的段/資源對齊大小。 與NE文件不同,PE文件通常沒有數百個部分,因此通過對齊文件部分而浪費的空間幾乎總是非常小。

編輯:磁盤上的所有部分大小也被向上舍入(填充)到FileAlignment的倍數。 來自http://www.openwatcom.org/ftp/devel/docs/pecoff.pdf

SizeOfRawData域

部分(目標文件)的大小或磁盤上初始化數據的大小(圖像文件)。 對於可執行映像,它必須是可選標頭中FileAlignment的倍數。 如果這小於VirtualSize,則該部分的其余部分為零填充。 因為此字段是四舍五入的,而VirtualSize字段不是,所以它也可能大於VirtualSize。 當某個部分僅包含未初始化的數據時,該字段應為0。

我假設即使是最后一部分也是如此填充,以便發出部分的鏈接器代碼然后加載它們的加載器代碼不必擔心最后一部分的大小的特殊情況。 無論如何修剪最后一個部分將是一個相當毫無意義的優化,因為磁盤扇區(以及該文件系統的較大集群頂部)具有內部碎片 ,可以消除任何此類“保存”(從修改最后一部分)大部分時間。

可執行文件包含許多部分。 如果我沒記錯的話,這些部分中的每一部分都與512字節對齊。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM