Car*_*los 16 c# garbage-collection finance
这是我在网上发现的一篇有趣的文章.
它讨论了该公司如何能够在托管环境中解析大量财务数据,主要是通过对象重用和避免不可变因素(如字符串).然后他们继续说明他们的程序在连续操作阶段没有做任何GC.
这是非常令人印象深刻的,我想知道这里是否有其他人有关于如何做到这一点的更详细的指导.首先,我想知道如何避免使用字符串,当消息中的某些数据是字符串时,无论客户端应用程序正在查看消息,都希望传递这些字符串?另外,你在启动阶段分配了什么?你怎么知道它够了?声明一大块内存并保留对它的引用以便GC不会启动是否很简单?客户端应用程序使用这些消息怎么样?是否还需要按照这些严格的标准编写?
另外,我需要一个特殊工具来查看内存吗?到目前为止,我一直在使用SciTech内存分析器.
我发现你所关联的论文相当缺乏:
当然,这并不意味着他们撒谎而且与垃圾收集无关,但它基本上意味着论文只是试图让人印象深刻,而不会泄露任何有用的东西来构建自己的东西.
从一开始就要注意的一点是,他们说"传统智慧一直在开发低延迟消息传递技术,需要使用非托管C++或汇编语言".特别是,他们谈论的是一种人们常常无法解雇.NET(或Java)解决方案的情况.就此而言,一个相对天真的C++解决方案可能也不会取得成绩.
这里要考虑的另一件事是,他们基本上已经没有那么多被GC取代它了 - 那里有管理对象生命周期的代码,但它是他们自己的代码.
有几种不同的方法可以做到这一点.这是一个.假设我需要在应用程序运行时创建和销毁几个Foo对象.Foo创建由int参数化,因此正常的代码将是:
public class Foo
{
private readonly int _bar;
Foo(int bar)
{
_bar = bar;
}
/* other code that makes this class actually interesting. */
}
public class UsesFoo
{
public void FooUsedHere(int param)
{
Foo baz = new Foo(param)
//Do something here
//baz falls out of scope and is liable to GC colleciton
}
}
Run Code Online (Sandbox Code Playgroud)
一种截然不同的方法是:
public class Foo
{
private static readonly Foo[] FOO_STORE = new Foo[MOST_POSSIBLY_NEEDED];
private static Foo FREE;
static Foo()
{
Foo last = FOO_STORE[MOST_POSSIBLY_NEEDED -1] = new Foo();
int idx = MOST_POSSIBLY_NEEDED - 1;
while(idx != 0)
{
Foo newFoo = FOO_STORE[--idx] = new Foo();
newFoo._next = FOO_STORE[idx + 1];
}
FREE = last._next = FOO_STORE[0];
}
private Foo _next;
//Note _bar is no longer readonly. We lose the advantages
//as a cost of reusing objects. Even if Foo acts immutable
//it isn't really.
private int _bar;
public static Foo GetFoo(int bar)
{
Foo ret = FREE;
FREE = ret._next;
return ret;
}
public void Release()
{
_next = FREE;
FREE = this;
}
/* other code that makes this class actually interesting. */
}
public class UsesFoo
{
public void FooUsedHere(int param)
{
Foo baz = Foo.GetFoo(param)
//Do something here
baz.Release();
}
}
Run Code Online (Sandbox Code Playgroud)
如果你是多线程的话,可以添加更多的复杂功能(虽然在非交互式环境中非常高性能,你可能希望每个线程有一个线程或单独的Foo类存储),如果你不能提前预测MOST_POSSIBLY_NEEDED(最简单的是根据需要创建新的Foo(),但不能为GC释放它们,如果FREE._next为null,则可以通过创建新的Foo在上面的代码中轻松完成.
如果我们允许不安全的代码,我们可以拥有更大的优势,使Foo成为一个结构(因此数组保持堆栈内存的连续区域),_next是指向Foo的指针,GetFoo()返回一个指针.
这是否是这些人实际做的事情,我当然不能说,但上述确实阻止了GC的激活.这只会在非常高的吞吐量条件下更快,如果不是那么让GC做它的东西可能更好(GC确实对你有帮助,尽管有90%的问题将它视为一个大坏事).
还有其他类似的方法可以避免使用GC.在C++中,可以重写new和delete运算符,这允许更改默认创建和销毁行为,并且讨论如何以及为什么这样做可能会让您感兴趣.
实际的一点是,当对象要么保存除了内存之外的资源(例如与数据库的连接),要么在继续使用它们时"学习"(例如XmlNameTables).在这种情况下,池化对象很有用(默认情况下,ADO.NET连接在幕后执行).在这种情况下,虽然简单的队列是要走的路,但内存方面的额外开销并不重要.您还可以放弃锁定争用中的对象(您希望获得性能,锁定争用会比放弃对象更伤害它),我怀疑它会在他们的情况下起作用.