beforefieldinit释义(3)
1.看下面的例子:
public static class MyClass<T>
{
public static readonly DateTime Time = GetNow();
private static DateTime GetNow()
{
Console.WriteLine("GetNow execute!");
return DateTime.Now;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main execute!");
Console.WriteLine("int: " + MyClass<int>.Time);
Thread.Sleep();
Console.WriteLine("string: " + MyClass<string>.Time);
Console.ReadLine();
}
}
结果如下:
GetNow execute!
GetNow execute!
Main execute!
int: 2009/9/8 15:34:31
string: 2009/9/8 15:34:31
看上面的结果在Main函数执行之前GetNow就执行了,就取到了DateTime.Now,所以输出的时间是一样的。
2.我们在上面的MyClass中加一个静态的构造函数我们在来看结果:
public static class MyClass<T>
{
public static readonly DateTime Time = GetNow();
private static DateTime GetNow()
{
Console.WriteLine("GetNow execute!");
return DateTime.Now;
}
static MyClass() { }
}
结果如下:
Main execute!
GetNow execute!
int: 2009/9/8 15:40:12
GetNow execute!
string: 2009/9/8 15:40:15
我们可以发现每次的时间不同了。出现这种现象是由于当类没有静态构造函数的时候。在il中该类会被标记为BeforeFieldInit,这个是由编译器自动完成的。没有静态构造函数的时候初始化在刚进入方法的时候就发生了,而有静态函数的时候而且我们不需要做任何动作,只要有就可以,这个时候静态初始化在使用前才发生.我们可以通过看IL代码来证实这种现象,如下:
![]()
3.使用BeforeFieldInit会提高性能,下面我们就测试下,在测试我们需要计算代码执行时间,我们就是用老赵的组件,我稍稍做了一点修改,因为老赵用的win32 API是vista下的,为了以后查询方便,也贴下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
namespace CSharpDemo
{
public static class CodeTimer
{
public static void Initialize()
{
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Time("", , () => { });
}
public static void Time(string name, int iteration, Action action)
{
if (String.IsNullOrEmpty(name)) return;
// 1.
ConsoleColor currentForeColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(name);
// 2.
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
int[] gcCounts = new int[GC.MaxGeneration + ];
for (int i = ; i <= GC.MaxGeneration; i++)
{
gcCounts[i] = GC.CollectionCount(i);
}
// 3.
Stopwatch watch = new Stopwatch();
watch.Start();
long cycleCount = GetCycleCount();
for (int i = ; i < iteration; i++) action();
long cpuCycles = GetCycleCount() - cycleCount;
watch.Stop();
// 4.
Console.ForegroundColor = currentForeColor;
Console.WriteLine("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
Console.WriteLine("\tCPU Cycles:\t" + cpuCycles.ToString("N0"));
// 5.
for (int i = ; i <= GC.MaxGeneration; i++)
{
int count = GC.CollectionCount(i) - gcCounts[i];
Console.WriteLine("\tGen " + i + ": \t\t" + count);
}
Console.WriteLine();
}
private static long GetCycleCount()
{
long l;
long kernelTime, userTimer;
GetThreadTimes(GetCurrentThread(), out l, out l, out kernelTime, out userTimer);
return kernelTime + userTimer;
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetThreadTimes(IntPtr hThread, out long lpCreationTime,
out long lpExitTime, out long lpKernelTime, out long lpUserTime);
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentThread();
}
}
下面我们开始测试,我们准备两个类:
public class MarkBeforeFieldInit
{
public static string test;
}
public class NoBeforeFieldInit
{
public static string test;
static NoBeforeFieldInit()
{
}
}
测试代码如下:
class Program
{
static void Main(string[] args)
{
CodeTimer.Initialize();
int iteration = * *;
CodeTimer.Time("MarkBeforeFieldInit", iteration, () => { MarkBeforeFieldInit.test = "test"; });
CodeTimer.Time("NoBeforeFieldInit", iteration, () => { NoBeforeFieldInit.test= "test"; });
CodeTimer.Time("MarkBeforeFieldInit2", iteration, () => { MarkBeforeFieldInit.test = "test"; });
CodeTimer.Time("NoBeforeFieldInit2", iteration, () => { NoBeforeFieldInit.test = "test"; });
}
}
结果如下:
![]()
![]()

可以看出BeforeFieldInit方式的执行速度确实快,但为什么第二次执行的速度差不多呢?因为经过第一次执行后JIT编译器知道类型的构造器已经被调用了,所以第二次执行时不会显示对构造函数进行调用。
beforefieldinit释义(3)的更多相关文章
- beforefieldinit释义(2)
首先来看一段代码: using System; namespace BeforeFieldInit { internal class Foo { Foo(){ Console.WriteLine(&q ...
- beforefieldinit释义
首先让我们认识什么是,当字段被标记为beforefieldinit类型时,该字段初始化可以发生在任何时候任何字段被引用之前.这句话听起了有点别扭,接下来让我们通过具体的例子介绍. /// <su ...
- 常见linux命令释义(第八天)—— Bash Shell 的操作环境
换了新公司,公司的领导很不错.自己感受比较多的地方是,自己的工作效率明显比以前高了.以前会对频繁变动的需求十分不耐烦,现在接到需求后会仔细的思考,进行整体构建.即使以后需求有变动,也能够比较轻易的在原 ...
- 常见linux命令释义(第三天)
今天晚上看鸟哥的私房菜,边学边写笔记. 在linux中压缩大多是.tar, .tar.gz , .tgz, /gz, .bz2等. .gz 是通过gzip压缩的文件. .bz2 是通过bzip2压缩的 ...
- 常见linux命令释义(第一天)
快到中午吃饭了,然后忽然想起来samba里面没有添加用户.于是乎,就玩弄起了samba. Samba三下五除二就安装好了,想想window里面不断的点击下一步,还要小心提防各种隐藏再角落里的绑定软件. ...
- Tomcat的目录结构、处理流程、主配置文件(server.xml)释义
参考资料: http://www.cnblogs.com/xdp-gacl/p/3744053.html http://grass51.blog.51cto.com/4356355/1123400 1 ...
- 使用Perl5获取有道词典释义
Get Word Definition from dict.youda.com via Perl Script 获取基本释义 Get Basic Definition http://dict.youd ...
- Web前端名词释义及原理
引言:看题目的时候,不要觉得这是一个很深奥的问题,Web前端这些东西很多就是叫的名字牛逼,其实原理很TM简单,也就那么回事. 一.javascript名词释义 1.啥是事件队列? 就是 弄一个数组,里 ...
- linux内核的冒险md来源释义# 14raid5非条块读
linux内核的冒险md来源释义# 14raid5非条块读 转载请注明出处:http://blog.csdn.net/liumangxiong 假设是非条块内读.那么就至少涉及到两个条块的读,这就须要 ...
随机推荐
- 【Java基础】foreach循环
从一个小程序说起: class lesson6foreach { public static void main(String[] args) { int array[]={2,3,1,5,4,6}; ...
- C#中对输出格式的初始化
一.在输出的时候,\t和8个空格是不一样的,\t是跳转到下一个水平制表符,如果你在第一个水平制表符中写有数据123,那么跳转后跳转到9的位置上,中间只有5个空格,但是如果用8个空格来做分割的话,就会有 ...
- poj-2403-cup
题目描述 The WHU ACM Team has a big cup, with which every member drinks water. Now, we know the volume o ...
- Fedora下用Iptux,中文乱码解决
Ubuntu/Fedora下用Iptux与Windows下大飞鸽传书,中文乱码解决 问题描述: 在Ubuntu/Fedora下安装了Iptux后,再往Windows机器上发送文件或消息时,如果有中文, ...
- Win7 64位系统上配置使用32位的Eclipse(转)
Win7 64位系统上配置使用32位的Eclipse 博客分类: Eclipse eclipse 最近工作电脑换成了64位的win7系统,之前个人电脑上安装的jdk和Eclipse都是32位的.而新 ...
- 时间的获取和转换,C#和Sql
我们可以通过使用DataTime这个类来获取当前的时间.通过调用类中的各种方法我们可以获取不同的时间:如:日期(2008-09-04).时间(12:12:12).日期+时间(2008-09-04 12 ...
- 班上有学生若干名,已知每名学生的成绩(整数),求班上所有学生的平均成绩,保留到小数点后两位。同时输出该平均成绩整数部分四舍五入后的数值。 第一行有一个整数n(1<= n <= 100),表示学生的人数。其后n行每行有1个整数,表示每个学生的成绩,取值在int范围内。
#include<iostream> #include<iomanip> using namespace std ; int main() { int n; while(cin ...
- (转)发现两个有用的C函数_alloca()、_msize()
转自: http://blog.csdn.net/pony12/article/details/8678071 (1)_alloca()alloca也是用来分配存储空间的,它和malloc的区别是它是 ...
- CKfinder中文乱码的解决.
最近在写一个类似博客的系统,使用了ckeditor和ckfinder,但是发现ckfinder在上传中文文件名的文件过程中会出现中文乱码的情况. 于是百度google乎,发现大多数的解决办法都是将文件 ...
- Windows Message Queue--hdu1509
Windows Message Queue Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Ot ...