XmlSerializer池字符串可以避免大的重复字符串吗?

gus*_*afc 5 .net c# memory-management xml-serialization

我有一些非常大的XML文件,我用它读取System.Xml.Serialization.XmlSerializer.它非常快(嗯,足够快),但我希望它能够汇集字符串,因为一些长字符串会出现很多次.

XML看起来有点像这样:

<Report>
    <Row>
        <Column name="A long column name!">hey</Column>
        <Column name="Another long column name!!">7</Column>
        <Column name="A third freaking long column name!!!">hax</Column>
        <Column name="Holy cow, can column names really be this long!?">true</Column>
    </Row>
    <Row>
        <Column name="A long column name!">yo</Column>
        <Column name="Another long column name!!">53</Column>
        <Column name="A third freaking long column name!!!">omg</Column>
        <Column name="Holy cow, can column names really be this long!?">true</Column>
    </Row>
    <!-- ... ~200k more rows go here... -->
</Report>
Run Code Online (Sandbox Code Playgroud)

XML被反序列化的类看起来像这样:

class Report 
{
    public Row[] Rows { get; set; }
}
class Row 
{
    public Column[] Columns { get; set; }
}
class Column 
{
    public string Name { get; set; }
    public string Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

导入数据时,会为每个列名分配一个新字符串.我可以看出为什么会这样,但根据我的计算,这意味着一些重复的字符串占导入数据使用的内存的约50%.我认为花一些额外的CPU周期来减少一半的内存消耗是一个非常好的权衡.有没有办法让XmlSerializer池字符串,以便重复被丢弃,并可以在下次gen0 GC发生时回收?


还有一些最后的说明:

  • 我无法更改XML架构.它是来自第三方供应商的导出文件.

  • 我知道可以(理论上)使用一个更快的解析器XmlReader,它不仅允许我自己进行字符串池化,而且还可以在导入中期处理数据,这样所有200k行都不能保存在RAM中直到我已经阅读了整个文件.不过,我宁愿不花时间编写和调试自定义解析器.真正的XML比示例复杂一点,所以这是一项非常重要的任务.如上所述 - XmlSerializer我的目的确实表现得非常好,我只是想知道是否有一种简单的方法来调整它.

  • 我可以编写一个自己的字符串池并在Column.Namesetter中使用它,但我不愿意(1)这意味着摆弄自动生成的代码,(2)它开启了一系列与并发相关的问题和内存泄漏.

  • 不,通过"汇集",我不是指"实习",因为这会导致内存泄漏.

Mar*_*ell 2

就我个人而言,我会毫不犹豫地手动启动实体 - 要么通过假设生成的代码的所有权,要么手动执行(并摆脱数组;-p)。

再并发——你也许可以有一个线程静态池?AFAIK,XmlSerializer只使用一个线程,所以这应该没问题。当你用完后,它还可以让你把游泳池扔掉。那么你就可以有一个类似静态池的东西,但是每个线程。然后也许调整设置器:

class Column 
{
    private string name, value;
    public string Name {
       get { return this.name; }
       set { this.name= MyPool.Get(value); }
    }
    public string Value{
       get { return this.value; }
       set { this.value = MyPool.Get(value); }
    }
}
Run Code Online (Sandbox Code Playgroud)

其中静态方法与用 装饰的MyPool.Get静态字段(大概是)进行对话。HashSet<string>[ThreadStatic]