日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

【转】深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第四节 参数传递对堆栈的影响 1

發布時間:2023/12/10 C# 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第四节 参数传递对堆栈的影响 1 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

?

雖然在.Net Framework 中我們不必考慮內在管理和垃圾回收(GC),但是為了優化應用程序性能我們始終需要了解內存管理和垃圾回收(GC)。另外,了解內存管理可以幫助我們理解在每一個程序中定義的每一個變量是怎樣工作的。

?

簡介

?

這篇文章我們將介紹一些方法參數傳遞行為在堆與棧中的影響。前幾節我們介紹了堆與棧的基本工作原理,程序執行時值類型與引用類型在堆棧中的存儲。另外,我們已經介紹了一些關于指針的基本知識。這一節中參數傳遞對堆棧的影響很重要,下面會慢慢道來。

?

參數,大畫面

下面是當代碼運行時會產生的一個詳細過程。上幾節已經介紹過當一個方法被調用時會產生的基本情況,讓我們來看一下更加詳細的內容。

當我們調用一個方法時會發生以下情形:

  • 棧會分配一塊內存空間給程序執行所需要的信息(我們叫它棧結構Stack Frame)。一個棧結構包含方法調用地址(指針),它以一個GOTO指令的形式存在棧里。因此,當程序執行完方法(method)時,它會知道怎么樣返回進而曳繼續執行代碼。
  • 方法的所有參數將被復制到棧里,這是我們將要更加詳細介紹的部分。
  • 控制被傳遞到JIT編譯過的方法里,同時線程開始執行代碼。此時,我們將有另一個方法呈現在棧結構的“回調棧”里。
  • 代碼:

    ?
  • public int AddFive(int pValue)

  • {

  • int result;

  • result = pValue + 5;

  • return result;

  • }


  • 棧像下圖所示:

    ?

    注意:ReturnValue方法不會存在棧上,圖中把ReturnValue作為此棧結構的開始只是為了解釋棧原理。

    ?

    像前幾節介紹的,值類型和引用類型在棧里的存儲是不同的。棧為任何值類型創建副本,棧也為任何引用類型的指針創建副本。

    ?

    值類型傳遞

    下面是值類型傳遞在棧里的內幕。

    ?

    首先,當我們傳遞一個值類型變量時,棧會為它分配一塊內存空間并把值類型變量的值存儲進去。看下面的代碼:

    ?
  • class Class1

  • {

  • public void Go()

  • {

  • int x = 5;

  • AddFive(x);

  • ?
  • Console.WriteLine(x.ToString());

  • ?
  • }

  • ?
  • public int AddFive(int pValue)

  • {

  • pValue += 5;

  • return pValue;

  • }

  • }


  • 當代碼執行時,棧為x分配一塊內存空間并存儲值5

    然后,AddFive()被放到棧上,同時棧分配內存空間給參數pValue并復制x的值給它。

    當AddFive()執行完成,線程被傳遞回Go()。同時因為AddFive()執行完,它的參數pValue也實質上被移除。

    所以結果是5是合理的。關鍵點是任何被傳遞的值類型參數僅是一個碳復制,因為我們希望保護原始變量的值。

    有一點要記住的是,如果我們有一個非常龐大的值類型(如,龐大的struct類型)傳遞到棧里,當處理器循環復制它并循環占有棧空間時將會非常耗資源。棧沒有無限的空間去使用,就像用水杯不斷的接水早晚會溢出一樣。Struct類型可以變得非常龐大,我們要小心并清醒的使用它。

    ?

    下面是一個比較大的struct結構類型:

    ?
  • public struct MyStruct

  • {

  • long a, b, c, d, e, f, g, h, i, j, k, l, m;

  • }


  • 讓我們看看執行下面代碼Go()方法時再到DoSomething()方法會發生的情況:

    ?
  • public void Go()

  • {

  • MyStruct x = new MyStruct();

  • DoSomething(x);

  • ?
  • }

  • ?
  • ?
  • public void DoSomething(MyStruct pValue)

  • {

  • // 省略具體實現....

  • }


  • 這可能會非常低效。想像一下如果我們傳遞MyStruct幾千次,它會怎么樣讓程序死掉。

    ?

    那么,我們怎么才能回避這樣的問題呢?那就是僅傳遞原始值類型的引用。

    public void Go()
    ? ? ? ? ? {
    ? ? ? ? ? ? ?MyStruct x = new MyStruct();
    ? ? ? ? ? ? ?DoSomething(ref?x);
    ? ? ? ? ? ? ??
    ? ? ? ? ? }
    ?
    ? ? ? ? ? ?public struct MyStruct
    ? ? ? ? ? ?{
    ? ? ? ? ? ? ? ?long a, b, c, d, e, f, g, h, i, j, k, l, m;
    ? ? ? ? ? ?}
    ?
    ? ? ? ? ? ?public void DoSomething(ref?MyStruct pValue)
    ? ? ? ? ? ?{
    ? ? ? ? ? ? ? ? ? ? // 省略實現....
    ? ? ? ? ? ?}

    ?

    ?

    這樣就能節省內存并提升內存使用效率

    ?

    唯一需要注意的是傳遞引用時我們在訪問原始變量x的值,任可對pValue的改變都會影響到x。

    下面的代碼會將x改變成"12345",因為pValue.a實際上指向原始x聲明時所在的內存地址。

    ?
  • public void Go()

  • {

  • MyStruct x = new MyStruct();

  • x.a = 5;

  • DoSomething(ref x);

  • ?
  • Console.WriteLine(x.a.ToString());

  • ?
  • }

  • ?
  • public void DoSomething(ref MyStruct pValue)

  • {

  • pValue.a = 12345;

  • }


  • 未完待續。。。

    ?

    ?

    翻譯:?http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory2B01142006125918PM/csharp_memory2B.aspx

    ?

    總結

    以上是生活随笔為你收集整理的【转】深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第四节 参数传递对堆栈的影响 1的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。