我最近开发了一个Rust库,试图提供对大型数据库的快速访问( Unicode字符数据库,它作为一个平面XML文件是160 to )。我也希望它有一个较小的占用空间,所以我使用了各种方法来缩小大小。最终的结果是,我有一系列静态切片,如下所示:
#[derive(Clone,Copy,Eq,PartialEq,Debug)]
pub enum UnicodeCategory {
UppercaseLetter,
LowercaseLetter,
TitlecaseLetter,
ModifierLetter,
OtherLetter,
NonspacingMark,
SpacingMark,
EnclosingMark,
DecimalNumber,
// ...
}
pub static UCD_CAT: &'static [((u8, u8, u8), (u8, u8, u8), UnicodeCategory)] =
&[((0, 0, 0), (0, 0, 31), UnicodeCategory::Control),
((0, 0, 32), (0, 0, 32), UnicodeCategory::SpaceSeparator),
((0, 0, 33), (0, 0, 35), UnicodeCategory::OtherPunctuation),
/* ... */];
// ...
pub static UCD_DECOMP_MAP: &'static [((u8, u8, u8), &'static [(u8, u8, u8)])] =
&[((0, 0, 160), &[(0, 0, 32)]),
((0, 0, 168), &[(0, 0, 32), (0, 3, 8)]),
((0, 0, 170), &[(0, 0, 97)]),
((0, 0, 175), &[(0, 0, 32), (0, 3, 4)]),
((0, 0, 178), &[(0, 0, 50)]),
/* ... */];总之,所有的数据应该只占600 total (假设有额外的对齐空间等),但是在发布模式下生成的库是3.3MB。源代码本身(几乎所有的数据)都是2.6MB,所以我不明白为什么结果会更多。我不认为额外的大小是内在的,因为大小是<50 2kB在项目开始(当我只有~2kB的数据)。如果有区别的话,我也会使用#![no_std]特性。
是否有任何理由额外的二进制膨胀,并有一个方法来缩小规模?从理论上讲,我不明白为什么不能将库减少到兆字节或更少。
根据马蒂厄的建议,我试着用nm分析二进制文件。
因为我的所有表都是用借来的片表示的,所以这对于计算表大小没有多大用处,因为它们都是用匿名的_ref来表示的。我能确定的是最大地址0x1208f8,它的文件大小为~1MB,而不是3.3MB。我还查看了十六进制转储,看看是否有任何空块可以解释它,但没有。
为了了解是否借来的切片是问题所在,我将它们转换为非借来的切片([T; N]表单)。文件大小变化不大,但现在我可以很容易地解释nm数据。奇怪的是,这些表占据了我对它们的期望(更奇怪的是,它们在不考虑对齐的情况下与我的下界相匹配,而且两张表之间没有空位)。
我还查看了带有嵌套借来的切片的表,例如上面的UCD_DECOMP_MAP。当我删除所有这些数据(约占数据的2/3 )时,文件大小为~1MB,而它本应仅为250‘t(根据我的计算和最高的nm地址0x3d1d0),所以看起来这些表也不是问题所在。
我尝试从.rlib文件(这是一个简单的ar格式存档)中提取各个文件。事实证明,40%的库只是元数据文件,而实际的对象文件是1.9MB。此外,当我在没有借用引用的情况下对库执行此操作时,对象文件是261 is!然后我回到原始库,查看单个_ref的大小,发现对于像UCD_DECOMP_MAP: &'static [((u8,u8,u8),&'static [(u8,u8,u8)])]这样的表,((u8,u8,u8),&'static [(u8,u8,u8)])类型的每个值占24个字节( u8三重奏为3个字节,填充为5个字节,指针为16个字节),因此这些表占用的空间比我想象的要大得多。我想我现在可以充分说明所有文件的大小。
当然,3MB仍然是相当小,我只是想保持文件尽可能小!
发布于 2016-07-23 22:59:54
感谢马蒂厄·M和克里斯·爱默生为我指明了解决方案。这是一个更新的问题摘要,抱歉的重复!
似乎有两个原因造成了所谓的膨胀:
.rlib文件不是纯对象文件,而是ar存档文件。通常,这样的文件将完全由一个或多个对象文件组成,但锈蚀也包括元数据。造成这种情况的部分原因似乎是为了避免需要单独的头文件。这约占最后文件大小的40%。nm,我可以发现,对于普通表(如UCD_CAT: &'static [((u8,u8,u8), (u8,u8,u8), UnicodeCategory)] ),每项的大小为7字节(实际上比我原先预期的要小,假设对齐为8字节)。所有这些表的总数约为230 of,而包含这些表的对象文件的大小为260 of(提取后),因此这一切都是一致的。
但是,更仔细地检查其他表(如nm )的UCD_DECOMP_MAP: &'static [((u8,u8,u8),&'static [(u8,u8,u8)])]输出比较困难,因为它们以匿名借用对象的形式出现。然而,事实证明,每个((u8,u8,u8),&'static [(u8,u8,u8)])实际上占24个字节:第一个元组为3个字节,填充为5个字节,指针为一个意外的16个字节。我相信这是因为指针还包括引用数组的大小。这给图书馆增加了大约一兆字节的膨胀,但似乎占了整个文件的比例。https://stackoverflow.com/questions/38544917
复制相似问题