C#中怎么快速內(nèi)存拷貝

本篇文章給大家分享的是有關(guān)C#中怎么快速內(nèi)存拷貝,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

創(chuàng)新互聯(lián)專注于治多網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供治多營(yíng)銷型網(wǎng)站建設(shè),治多網(wǎng)站制作、治多網(wǎng)頁(yè)設(shè)計(jì)、治多網(wǎng)站官網(wǎng)定制、微信小程序定制開(kāi)發(fā)服務(wù),打造治多網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供治多網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。

首先你需要?jiǎng)?chuàng)建一個(gè)默認(rèn)的Windows Forms應(yīng)用程序工程,在窗體上放兩個(gè)按鈕,一個(gè)PictureBox 控件,因?yàn)槲覀儗⒂脠D片來(lái)測(cè)試。

聲明幾個(gè)字段先:

string bitmapPath;  Bitmap bmp, bmp2;  BitmapData bmpd, bmpd2;  byte[] buffer = null;

現(xiàn)在創(chuàng)建兩個(gè)方法用來(lái)處理按鈕的點(diǎn)擊事件。

標(biāo)準(zhǔn)方法如下:

private void btnStandard_Click(object sender, EventArgs e)  {          using (OpenFileDialog ofd = new OpenFileDialog())          {              if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK)                  return;                 bitmapPath = ofd.FileName;          }       //open a selected image and create an empty image with the same size          OpenImage();       //unlock for read and write images          UnlockBitmap();       //copy data from one image to another by standard method          CopyImage();       //lock images to be able to see them          LockBitmap();       //lets see what we have          pictureBox1.Image = bmp2;  }

快速方法如下:

private void btnFast_Click(object sender, EventArgs e)  {    using (OpenFileDialog ofd = new OpenFileDialog())          {              if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK)                  return;              bitmapPath = ofd.FileName;          }       //open a selected image and create an empty image with the same size          OpenImage();       //unlock for read and write images          UnlockBitmap();       //copy data from one image to another with our fast method          FastCopyImage();       //lock images to be able to see them          LockBitmap();       //lets see what we have          pictureBox1.Image = bmp2;  }

好的,現(xiàn)在我們有按鈕并且也有了事件處理,下面來(lái)實(shí)現(xiàn)打開(kāi)圖片、鎖定、解鎖它們的方法,以及標(biāo)準(zhǔn)拷貝方法:

打開(kāi)一個(gè)圖片:

void OpenImage()  {    pictureBox1.Image = null;    buffer = null;    if (bmp != null)    {      bmp.Dispose();      bmp = null;    }    if (bmp2 != null)    {      bmp2.Dispose();      bmp2 = null;    }    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);       bmp = (Bitmap)Bitmap.FromFile(bitmapPath);       buffer = new byte[bmp.Width * 4 * bmp.Height];    bmp2 = new Bitmap(bmp.Width, bmp.Height, bmp.Width * 4, PixelFormat.Format32bppArgb,      Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0));  }

鎖定和解鎖位圖:

void UnlockBitmap()  {    bmpd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite,       PixelFormat.Format32bppArgb);    bmpd2 = bmp2.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite,       PixelFormat.Format32bppArgb);  }     void LockBitmap()  {    bmp.UnlockBits(bmpd);    bmp2.UnlockBits(bmpd2);  }

從一個(gè)圖片拷貝數(shù)據(jù)到另一個(gè)圖片,并且顯示測(cè)得的時(shí)間:

void CopyImage()  {    //start stopwatch    Stopwatch sw = new Stopwatch();    sw.Start();       //copy-past data 10 times    for (int i = 0; i < 10; i++)    {      System.Runtime.InteropServices.Marshal.Copy(bmpd.Scan0, buffer, 0, buffer.Length);    }       //stop stopwatch    sw.Stop();       //show measured time    MessageBox.Show(sw.ElapsedTicks.ToString());  }

這就是標(biāo)準(zhǔn)快速拷貝方法。其實(shí)一點(diǎn)也不復(fù)雜,我們使用了知名的  System.Runtime.InteropServices.Marshal.Copy   方法。

以及又一個(gè)“中間方法(middle-method)”以用于快速拷貝邏輯:

void FastCopyImage()  {    FastMemCopy.FastMemoryCopy(bmpd.Scan0, bmpd2.Scan0, buffer.Length);  }

現(xiàn)在,來(lái)實(shí)現(xiàn)FastMemCopy類。下面是類的聲明以及我們將會(huì)在類中使用到的一些類型:

internal static class FastMemCopy  {    [Flags]    private enum AllocationTypes : uint   {      Commit = 0x1000,  Reserve = 0x2000,      Reset = 0x80000,  LargePages = 0x20000000,      Physical = 0x400000,  TopDown = 0x100000,      WriteWatch = 0x200000    }       [Flags]    private enum MemoryProtections : uint   {      Execute = 0x10,      ExecuteRead = 0x20,      ExecuteReadWrite = 0x40,  ExecuteWriteCopy = 0x80,      NoAccess = 0x01,    ReadOnly = 0x02,      ReadWrite = 0x04,    WriteCopy = 0x08,      GuartModifierflag = 0x100,  NoCacheModifierflag = 0x200,      WriteCombineModifierflag = 0x400    }       [Flags]    private enum FreeTypes : uint   {      Decommit = 0x4000,  Release = 0x8000    }       [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]    private unsafe delegate void FastMemCopyDelegate();       private static class NativeMethods    {      [DllImport("kernel32.dll", SetLastError = true)]      internal static extern IntPtr VirtualAlloc(        IntPtr lpAddress,        UIntPtr dwSize,        AllocationTypes flAllocationType,        MemoryProtections flProtect);         [DllImport("kernel32")]      [return: MarshalAs(UnmanagedType.Bool)]      internal static extern bool VirtualFree(        IntPtr lpAddress,        uint dwSize,        FreeTypes flFreeType);    }

現(xiàn)在聲明方法本身:

public static unsafe void FastMemoryCopy(IntPtr src, IntPtr dst, int nBytes)  {    if (IntPtr.Size == 4)          {                  //we are in 32 bit mode                     //allocate memory for our asm method                  IntPtr p = NativeMethods.VirtualAlloc(                      IntPtr.Zero,                      new UIntPtr((uint)x86_FastMemCopy_New.Length),                      AllocationTypes.Commit | AllocationTypes.Reserve,                      MemoryProtections.ExecuteReadWrite);                     try                 {                      //copy our method bytes to allocated memory                      Marshal.Copy(x86_FastMemCopy_New, 0, p, x86_FastMemCopy_New.Length);                         //make a delegate to our method                      FastMemCopyDelegate _fastmemcopy =         (FastMemCopyDelegate)Marshal.GetDelegateForFunctionPointer(p,           typeof(FastMemCopyDelegate));                         //offset to the end of our method block                      p += x86_FastMemCopy_New.Length;                         //store length param                      p -= 8;                      Marshal.Copy(BitConverter.GetBytes((long)nBytes), 0, p, 4);                         //store destination address param                      p -= 8;                      Marshal.Copy(BitConverter.GetBytes((long)dst), 0, p, 4);                         //store source address param                      p -= 8;                      Marshal.Copy(BitConverter.GetBytes((long)src), 0, p, 4);                         //Start stopwatch                      Stopwatch sw = new Stopwatch();                      sw.Start();                         //copy-past all data 10 times                      for (int i = 0; i < 10; i++)                          _fastmemcopy();                         //stop stopwatch                      sw.Stop();                         //get message with measured time                      System.Windows.Forms.MessageBox.Show(sw.ElapsedTicks.ToString());                  }                  catch (Exception ex)                  {                      //if any exception                      System.Windows.Forms.MessageBox.Show(ex.Message);                  }                  finally                 {                      //free allocated memory                      NativeMethods.VirtualFree(p, (uint)(x86_FastMemCopy_New.Length),         FreeTypes.Release);                      GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);                  }    }    else if (IntPtr.Size == 8)          {                  throw new ApplicationException("x64 is not supported yet!");    }  }

匯編代碼被表示成帶注釋的字節(jié)數(shù)組:

private static byte[] x86_FastMemCopy_New = new byte[]  {    0x90, //nop do nothing    0x60, //pushad store flag register on stack    0x95, //xchg ebp, eax eax contains memory address of our method    0x8B, 0xB5, 0x***, 0x01, 0x00, 0x00, //mov esi,[ebp][0000001***] get source buffer address    0x89, 0xF0, //mov eax,esi    0x83, 0xE0, 0x0F, //and eax,00F will check if it is 16 byte aligned    0x8B, 0xBD, 0x62, 0x01, 0x00, 0x00, //mov edi,[ebp][000000162] get destination address    0x89, 0xFB, //mov ebx,edi    0x83, 0xE3, 0x0F, //and ebx,00F will check if it is 16 byte aligned    0x8B, 0x8D, 0x6A, 0x01, 0x00, 0x00, //mov ecx,[ebp][00000016A] get number of bytes to copy    0xC1, 0xE9, 0x07, //shr ecx,7 divide length by 128    0x85, 0xC9, //test ecx,ecx check if zero    0x0F, 0x84, 0x1C, 0x01, 0x00, 0x00, //jz 000000146 &darr; copy the rest    0x0F, 0x18, 0x06, //prefetchnta [esi] pre-fetch non-temporal source data for reading    0x85, 0xC0, //test eax,eax check if source address is 16 byte aligned    0x0F, 0x84, 0x8B, 0x00, 0x00, 0x00, //jz 0000000C0 &darr; go to copy if aligned    0x0F, 0x18, 0x86, 0x80, 0x02, 0x00, 0x00, //prefetchnta [esi][000000280] pre-fetch more source data    0x0F, 0x10, 0x06, //movups xmm0,[esi] copy 16 bytes of source data    0x0F, 0x10, 0x4E, 0x10, //movups xmm1,[esi][010] copy more 16 bytes    0x0F, 0x10, 0x56, 0x20, //movups xmm2,[esi][020] copy more    0x0F, 0x18, 0x86, 0xC0, 0x02, 0x00, 0x00, //prefetchnta [esi][0000002C0] pre-fetch more    0x0F, 0x10, 0x5E, 0x30, //movups xmm3,[esi][030]    0x0F, 0x10, 0x66, 0x40, //movups xmm4,[esi][040]    0x0F, 0x10, 0x6E, 0x50, //movups xmm5,[esi][050]    0x0F, 0x10, 0x76, 0x60, //movups xmm6,[esi][060]    0x0F, 0x10, 0x7E, 0x70, //movups xmm7,[esi][070] we&apos;ve copied 128 bytes of source data    0x85, 0xDB, //test ebx,ebx check if destination address is 16 byte aligned    0x74, 0x21, //jz 000000087 &darr; go to past if aligned    0x0F, 0x11, 0x07, //movups [edi],xmm0 past first 16 bytes to non-aligned destination address    0x0F, 0x11, 0x4F, 0x10, //movups [edi][010],xmm1 past more    0x0F, 0x11, 0x57, 0x20, //movups [edi][020],xmm2    0x0F, 0x11, 0x5F, 0x30, //movups [edi][030],xmm3    0x0F, 0x11, 0x67, 0x40, //movups [edi][040],xmm4    0x0F, 0x11, 0x6F, 0x50, //movups [edi][050],xmm5    0x0F, 0x11, 0x77, 0x60, //movups [edi][060],xmm6    0x0F, 0x11, 0x7F, 0x70, //movups [edi][070],xmm7 we&apos;ve pasted 128 bytes of source data    0xEB, 0x1F, //jmps 0000000A6 &darr; continue    0x0F, 0x2B, 0x07, //movntps [edi],xmm0 past first 16 bytes to aligned destination address    0x0F, 0x2B, 0x4F, 0x10, //movntps [edi][010],xmm1 past more    0x0F, 0x2B, 0x57, 0x20, //movntps [edi][020],xmm2    0x0F, 0x2B, 0x5F, 0x30, //movntps [edi][030],xmm3    0x0F, 0x2B, 0x67, 0x40, //movntps [edi][040],xmm4    0x0F, 0x2B, 0x6F, 0x50, //movntps [edi][050],xmm5    0x0F, 0x2B, 0x77, 0x60, //movntps [edi][060],xmm6    0x0F, 0x2B, 0x7F, 0x70, //movntps [edi][070],xmm7 we&apos;ve pasted 128 bytes of source data    0x81, 0xC6, 0x80, 0x00, 0x00, 0x00, //add esi,000000080 increment source address by 128    0x81, 0xC7, 0x80, 0x00, 0x00, 0x00, //add edi,000000080 increment destination address by 128    0x83, 0xE9, 0x01, //sub ecx,1 decrement counter    0x0F, 0x85, 0x7A, 0xFF, 0xFF, 0xFF, //jnz 000000035 &uarr; continue if not zero    0xE9, 0x86, 0x00, 0x00, 0x00, //jmp 000000146 &darr; go to copy the rest of data       0x0F, 0x18, 0x86, 0x80, 0x02, 0x00, 0x00, //prefetchnta [esi][000000280] pre-fetch source data    0x0F, 0x28, 0x06, //movaps xmm0,[esi] copy 128 bytes from aligned source address    0x0F, 0x28, 0x4E, 0x10, //movaps xmm1,[esi][010] copy more    0x0F, 0x28, 0x56, 0x20, //movaps xmm2,[esi][020]    0x0F, 0x18, 0x86, 0xC0, 0x02, 0x00, 0x00, //prefetchnta [esi][0000002C0] pre-fetch more data    0x0F, 0x28, 0x5E, 0x30, //movaps xmm3,[esi][030]    0x0F, 0x28, 0x66, 0x40, //movaps xmm4,[esi][040]    0x0F, 0x28, 0x6E, 0x50, //movaps xmm5,[esi][050]    0x0F, 0x28, 0x76, 0x60, //movaps xmm6,[esi][060]    0x0F, 0x28, 0x7E, 0x70, //movaps xmm7,[esi][070] we&apos;ve copied 128 bytes of source data    0x85, 0xDB, //test ebx,ebx check if destination address is 16 byte aligned    0x74, 0x21, //jz 000000112 &darr; go to past if aligned    0x0F, 0x11, 0x07, //movups [edi],xmm0 past 16 bytes to non-aligned destination address    0x0F, 0x11, 0x4F, 0x10, //movups [edi][010],xmm1 past more    0x0F, 0x11, 0x57, 0x20, //movups [edi][020],xmm2    0x0F, 0x11, 0x5F, 0x30, //movups [edi][030],xmm3    0x0F, 0x11, 0x67, 0x40, //movups [edi][040],xmm4    0x0F, 0x11, 0x6F, 0x50, //movups [edi][050],xmm5    0x0F, 0x11, 0x77, 0x60, //movups [edi][060],xmm6    0x0F, 0x11, 0x7F, 0x70, //movups [edi][070],xmm7 we&apos;ve pasted 128 bytes of data    0xEB, 0x1F, //jmps 000000131 &darr; continue copy-past    0x0F, 0x2B, 0x07, //movntps [edi],xmm0 past 16 bytes to aligned destination address    0x0F, 0x2B, 0x4F, 0x10, //movntps [edi][010],xmm1 past more    0x0F, 0x2B, 0x57, 0x20, //movntps [edi][020],xmm2    0x0F, 0x2B, 0x5F, 0x30, //movntps [edi][030],xmm3    0x0F, 0x2B, 0x67, 0x40, //movntps [edi][040],xmm4    0x0F, 0x2B, 0x6F, 0x50, //movntps [edi][050],xmm5    0x0F, 0x2B, 0x77, 0x60, //movntps [edi][060],xmm6    0x0F, 0x2B, 0x7F, 0x70, //movntps [edi][070],xmm7 we&apos;ve pasted 128 bytes of data    0x81, 0xC6, 0x80, 0x00, 0x00, 0x00, //add esi,000000080 increment source address by 128    0x81, 0xC7, 0x80, 0x00, 0x00, 0x00, //add edi,000000080 increment destination address by 128    0x83, 0xE9, 0x01, //sub ecx,1 decrement counter    0x0F, 0x85, 0x7A, 0xFF, 0xFF, 0xFF, //jnz 0000000C0 &uarr; continue copy-past if non-zero    0x8B, 0x8D, 0x6A, 0x01, 0x00, 0x00, //mov ecx,[ebp][00000016A] get number of bytes to copy    0x83, 0xE1, 0x7F, //and ecx,07F get rest number of bytes    0x85, 0xC9, //test ecx,ecx check if there are bytes    0x74, 0x02, //jz 000000155 &darr; exit if there are no more bytes    0xF3, 0xA4, //rep movsb copy rest of bytes    0x0F, 0xAE, 0xF8, //sfence performs a serializing operation on all store-to-memory instructions    0x61, //popad restore flag register    0xC3, //retn return from our method to C#         0x00, 0x00, 0x00, 0x00, //source buffer address    0x00, 0x00, 0x00, 0x00,       0x00, 0x00, 0x00, 0x00, //destination buffer address    0x00, 0x00, 0x00, 0x00,       0x00, 0x00, 0x00, 0x00, //number of bytes to copy-past    0x00, 0x00, 0x00, 0x00  };

以上就是C#中怎么快速內(nèi)存拷貝,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

文章題目:C#中怎么快速內(nèi)存拷貝
本文路徑:http://bm7419.com/article30/gejhpo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App設(shè)計(jì)、外貿(mào)建站關(guān)鍵詞優(yōu)化、動(dòng)態(tài)網(wǎng)站、Google商城網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化