淺談Go中的Pointer和記憶體管理

閱讀時間約 9 分鐘


raw-image

👨‍💻簡介

當我們在宣告變數時,電腦會為該變數在記憶體中分配一個位置,然後將這個變數值儲存在這個位置上,需要讀取或修改這個變數值時,電腦是透過記憶體位置來存取這個值。 今天來簡單介紹一下go的Pointer,他的特性以及常見用法。

什麼是Pointer?

Pointer是一種資料類型,用來儲存變數的記憶體地址。在Go中,我們可以通過使用 * 符號來宣告和操作Pointer。這允許我們直接訪問和修改變數的內容,而不僅僅是讀取或複製它們的值。

Pointer的特性、限制與常見用法

特性

  • Pointer的值和地址

每個變數都有一個記憶體地址,我們可以使用Pointer變數來儲存這個地址。讓我們看一個範例:

package main

import "fmt"
func main() {
x := 42
var p *int // 宣告一個整數Pointer
p = &x // 將p指向x的地址
fmt.Println("x =", x)
fmt.Println("p =", p)
}

在這個例子中,我們創建了一個整數變數 x,並宣告了一個整數Pointer p,然後將 p 設為 x 的地址。現在,p 裡面存放的就是 x 的地址。

  • Pointer的初始化

Go中的Pointer可以通過 new 函數來初始化,這將為指定的類型分配記憶體並返回其地址。範例:

package main

import "fmt"
func main() {
var p *int
p = new(int) // 初始化一個整數Pointer
*p = 123 // 將Pointer所指向的記憶體設置為123
fmt.Println("*p =", *p)
}

可以看到,我們創建了一個整數Pointer p,並使用 new(int) 初始化它,然後將 p 所指向的記憶體設置為 123

  • Pointer的解引用

通過Pointer,我們可以訪問和修改變數的值,這稱為Pointer的解引用。

package main

import "fmt"
func main() {
x := 42
p := &x // 將p設為x的地址,使用&
fmt.Println("x =", x)
fmt.Println("&x =", &x)
fmt.Println("*p =", *p) // 解引用Pointer,獲得x的值,使用*
*p = 99 // 通過Pointer修改x的值
fmt.Println("x =", x) // x的值已被修改
fmt.Println("&x =", &x)
fmt.Println("*p =", *p)
}

在這個例子中,我們使用Pointer p 解引用,並修改了變數 x 的值。也可以觀察到修改值並不會改變記憶體位置。

限制

  1. 空Pointer風險:未初始化的Pointer可能為nil,試圖解引用nil Pointer會導致運行時錯誤(panic)。
  2. 記憶體管理:Go中的垃圾回收器會管理記憶體,但Pointer仍然需要謹慎使用,以避免記憶體錯誤。
  3. 競爭條件:多線程環境中,共享的Pointer可能導致競爭條件,需要使用互斥鎖等技術來保護共享資源。

常見用法

  • 節省記憶體

當需要處理大型資料結構時,使用Pointer可以節省記憶體,因為它們只儲存變數的地址,而不是整個資料。

package main

import (
"fmt"
"unsafe"
)
// 定義一個名為 Person 的結構(struct)
type Person struct {
Name string // 名稱
Age int // 年齡
}
func main() {
// 創建一個 Person 變數,名稱為 Alice,年齡為 30 歲
alice := Person{Name: "Alice", Age: 30}
// 計算 Person 變數 alice 的大小
personSize := unsafe.Sizeof(alice)
// 創建一個指向 Person 變數的Pointer,名稱為 Bob,年齡為 24 歲
bob := &Person{Name: "Bob", Age: 24}
// 計算指向 Person 變數 bob 的Pointer的大小
pointerSize := unsafe.Sizeof(bob)
fmt.Printf("alice -> Person 變數的大小: %d 個位元組\n", personSize)
fmt.Printf("bob -> 指向 Person 變數的Pointer的大小: %d 個位元組\n", pointerSize)
fmt.Println(&alice) // 列印 alice 變數的記憶體位置
fmt.Println(&bob) // 列印 bob 變數(Pointer)的記憶體位置
}

在上面的範例中,我們透過兩種方式創建person,但可以觀察到使用Pointer的方式創建,使用的大小較小,達到節省記憶體的作用。

  • 改變資料的原始值

想要在函數中修改變數的值,而不只是副本時,Pointer變得非常有用。

package main

import "fmt"
func modifyValue(x *int) {
*x = 100
}
func main() {
y := 10
modifyValue(&y) // 通過Pointer修改y的值
fmt.Println("y =", y)
}
  • 效能優勢

在某些情況下,使用Pointer可以提高性能,因為它們允許直接訪問和修改記憶體,而不需要額外的記憶體複製操作。

package main

import (
"fmt"
"time"
)
const N = 1000000 // 陣列大小
// 使用值傳遞的函數,不使用指標
func sumValues(arr [N]int) int {
sum := 0
for _, v := range arr {
sum += v
}
return sum
}
// 使用指標傳遞的函數,避免陣列複製
func sumPointers(arr *[N]int) int {
sum := 0
for _, v := range arr {
sum += v
}
return sum
}
func main() {
// 創建一個包含大量資料的整數陣列
var arr [N]int
for i := 0; i < N; i++ {
arr[i] = i
}
// 測試不使用指標的情況,複製陣列
startTime := time.Now()
result1 := sumValues(arr)
duration1 := time.Since(startTime)
// 測試使用指標的情況,避免複製陣列
startTime = time.Now()
result2 := sumPointers(&arr)
duration2 := time.Since(startTime)
fmt.Printf("不使用指標的結果:%d,執行時間:%v\n", result1, duration1)
fmt.Printf("使用指標的結果:%d,執行時間:%v\n", result2, duration2)
}

可以看到,我們創建了一個包含大量資料的整數陣列,並寫了兩個函數來計算陣列中所有元素的總和。一個函數 sumValues 使用值傳遞陣列,另一個函數 sumPointers 使用指標傳遞陣列。

在 main 函數中,測試了這兩個函數的效能。結果顯示,使用指標傳遞陣列可以明顯提高效能,因為它少了陣列的複製,節省了大量的時間和記憶體。

小結

Pointer是程式語言中的重要概念,它允許我們直接訪問和修改變數的內容,並在許多情況下提供性能優勢和節省記憶體的機會。但還是要小心使用Pointer,確保程式碼的穩定性和安全性。

📚Reference

17會員
81Content count
golang
留言0
查看全部
發表第一個留言支持創作者!
wang alan的沙龍 的其他內容
👨‍💻簡介 在軟體開發中,錯誤無所不在。無論是網路請求失敗、檔案不存在,還是數學計算錯誤,處理錯誤是任何開發者的日常工作,系統的穩定度基本取決於對於錯誤處理是否全面,好的錯誤處理也可以產生適當的錯誤訊息,讓 Debug 更加容易。
👨‍💻簡介 當我們在寫程式時,有時候會需要在程式結束時關閉某些資源,而defer這個關鍵字,可以讓你輕鬆的實現,下面來簡單介紹一下defer以及常用的範例。,它為程式設計師提供了一種簡單而強大的工具,用於管理資源和確保程式的正確執行。
👨‍💻簡介 在Go中,假如我要判斷一個資料類型是甚麼,該怎麼做呢? Golang有一個功能叫做Type Assertions(類型斷言),它的作用就是能夠在運行時檢查我的資料類型,讓我在傳遞類型時能確保資料類型是正確的。
👨‍💻簡介 make函數在slice、map和之後會介紹到的channel的初始化中扮演著關鍵的角色。本文將會簡單介紹make函數的用法,以及在初始化不同資料結構時的差異,讓你更好地理解和利用make函數。
👨‍💻簡介 套件(Package)在Golang中扮演著組織和管理程式碼的重要角色。 package就像工具箱一樣,裡面裝滿各種不同的工具,每個工具都有特定的功能。這些工具能夠幫助你完成不同的任務,從修理家具到蓋小屋,樣樣都行。
👨‍💻簡介 在Go語言中,Interface 是一個重要且強大的概念。Interface提供了一種方式來定義對象之間的契約,讓你可以設計更具有靈活性和可擴展性的程式碼。 你可以把Interface想像成是一種約定,讓不同的東西彼此溝通的方式變得特別靈活和好擴充,告訴程式裡的各個元件彼此要怎麼合作
👨‍💻簡介 在軟體開發中,錯誤無所不在。無論是網路請求失敗、檔案不存在,還是數學計算錯誤,處理錯誤是任何開發者的日常工作,系統的穩定度基本取決於對於錯誤處理是否全面,好的錯誤處理也可以產生適當的錯誤訊息,讓 Debug 更加容易。
👨‍💻簡介 當我們在寫程式時,有時候會需要在程式結束時關閉某些資源,而defer這個關鍵字,可以讓你輕鬆的實現,下面來簡單介紹一下defer以及常用的範例。,它為程式設計師提供了一種簡單而強大的工具,用於管理資源和確保程式的正確執行。
👨‍💻簡介 在Go中,假如我要判斷一個資料類型是甚麼,該怎麼做呢? Golang有一個功能叫做Type Assertions(類型斷言),它的作用就是能夠在運行時檢查我的資料類型,讓我在傳遞類型時能確保資料類型是正確的。
👨‍💻簡介 make函數在slice、map和之後會介紹到的channel的初始化中扮演著關鍵的角色。本文將會簡單介紹make函數的用法,以及在初始化不同資料結構時的差異,讓你更好地理解和利用make函數。
👨‍💻簡介 套件(Package)在Golang中扮演著組織和管理程式碼的重要角色。 package就像工具箱一樣,裡面裝滿各種不同的工具,每個工具都有特定的功能。這些工具能夠幫助你完成不同的任務,從修理家具到蓋小屋,樣樣都行。
👨‍💻簡介 在Go語言中,Interface 是一個重要且強大的概念。Interface提供了一種方式來定義對象之間的契約,讓你可以設計更具有靈活性和可擴展性的程式碼。 你可以把Interface想像成是一種約定,讓不同的東西彼此溝通的方式變得特別靈活和好擴充,告訴程式裡的各個元件彼此要怎麼合作
你可能也想看
Thumbnail
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
職場上平常大家都不計較...或者說建立在員工單方面忍耐,才維持一個「假平衡」 小蝦米的員工,在興起訴訟對簿公堂打破平衡前,先想清楚自己究竟想得到什麼? 是證明自己無罪的「道德價值」? 金錢? 對公司出一口氣? 唯有先想清楚才能不在訴訟之路迷失。
Thumbnail
肌力體能訓練是所有運動的基礎,能提升專項運動表現及降低運動傷害。本文深入探討肌力、健力與健美的區別,並解釋為何定期的肌力訓練對於普通運動者及專項運動員都至關重要。從古老的運動科學研究到現代訓練方法,這篇文章將幫助讀者理解正確的訓練方法,並消除對健身訓練的常見誤解。
Thumbnail
《黑神話:悟空》的開發團隊和採用的引擎技術確實很強,但最近滿多包裝成技術文的吹捧文,本文嘗試做簡單的評析。
Thumbnail
倪海厦老师在天纪中提到了很多种断卦方法,这里只选取几个简单的方法进行概括,总结和简化,没有任何关于倪海厦老师知识的文章可以比得上倪海厦老师的原视频,建议各位看官从原视频中吸取更多好方法。
Thumbnail
上篇文章我們解說到了神經網路的基本架構包含了輸入層,輸出層,還有中間的隱藏層,也說明了這是一個把輸入資料拆解出特徵然後依照特徵做判斷的過程。究竟每一層的神經網路,如何影響下一層的神經網路可以辨識出特徵呢? 這些中間的線條(連結)到底是什麼意義呢? 這就是這一篇要告訴你的。
Thumbnail
在我的上一篇文章中,我們提到了人工智慧 & 機器學習 & 深度學習跟神經網路的關係,我們也了解到了所謂的深度學習是一種基於神經網路上的機器學習方法。那麼神經網路到底是什麼呢? 我們上一篇文章裡面提到的神經網路的層Layer究竟是什麼呢? 到底為什麼神經網路需要這麼多的神經元(Neurons)跟層數呢
昨晚睡觉前,我把手机放在枕头边,躺在床上,听Youtbue 上,一位叫做LT视界的大咖讲解沈栋发表的《红色赌盘》中的一些细节。 这位大咖的分析非常到位。我之前也听过很多沈栋在台湾的访谈节目。我当初对于这位作者的印象还不错,觉得他思路很敏捷,谈吐不凡,见识广,的确是很有感染力,吸引力和洞察力。是个了不
Thumbnail
這週末(12/10~12/11)孩子的學校有籃球比賽,比較像是友誼賽。6個學校的籃球隊來進行友誼慈善賽。基本上在紐約高中的比賽多半都要付錢進去看。今年開始,學校恢復正常,比賽活動就可以進場看。賽季的比賽都在平日4,5點,看孩子打球的機會不大。 紐約市來說,Brooklyn的球隊比較強。我們在Qu
Thumbnail
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
職場上平常大家都不計較...或者說建立在員工單方面忍耐,才維持一個「假平衡」 小蝦米的員工,在興起訴訟對簿公堂打破平衡前,先想清楚自己究竟想得到什麼? 是證明自己無罪的「道德價值」? 金錢? 對公司出一口氣? 唯有先想清楚才能不在訴訟之路迷失。
Thumbnail
肌力體能訓練是所有運動的基礎,能提升專項運動表現及降低運動傷害。本文深入探討肌力、健力與健美的區別,並解釋為何定期的肌力訓練對於普通運動者及專項運動員都至關重要。從古老的運動科學研究到現代訓練方法,這篇文章將幫助讀者理解正確的訓練方法,並消除對健身訓練的常見誤解。
Thumbnail
《黑神話:悟空》的開發團隊和採用的引擎技術確實很強,但最近滿多包裝成技術文的吹捧文,本文嘗試做簡單的評析。
Thumbnail
倪海厦老师在天纪中提到了很多种断卦方法,这里只选取几个简单的方法进行概括,总结和简化,没有任何关于倪海厦老师知识的文章可以比得上倪海厦老师的原视频,建议各位看官从原视频中吸取更多好方法。
Thumbnail
上篇文章我們解說到了神經網路的基本架構包含了輸入層,輸出層,還有中間的隱藏層,也說明了這是一個把輸入資料拆解出特徵然後依照特徵做判斷的過程。究竟每一層的神經網路,如何影響下一層的神經網路可以辨識出特徵呢? 這些中間的線條(連結)到底是什麼意義呢? 這就是這一篇要告訴你的。
Thumbnail
在我的上一篇文章中,我們提到了人工智慧 & 機器學習 & 深度學習跟神經網路的關係,我們也了解到了所謂的深度學習是一種基於神經網路上的機器學習方法。那麼神經網路到底是什麼呢? 我們上一篇文章裡面提到的神經網路的層Layer究竟是什麼呢? 到底為什麼神經網路需要這麼多的神經元(Neurons)跟層數呢
昨晚睡觉前,我把手机放在枕头边,躺在床上,听Youtbue 上,一位叫做LT视界的大咖讲解沈栋发表的《红色赌盘》中的一些细节。 这位大咖的分析非常到位。我之前也听过很多沈栋在台湾的访谈节目。我当初对于这位作者的印象还不错,觉得他思路很敏捷,谈吐不凡,见识广,的确是很有感染力,吸引力和洞察力。是个了不
Thumbnail
這週末(12/10~12/11)孩子的學校有籃球比賽,比較像是友誼賽。6個學校的籃球隊來進行友誼慈善賽。基本上在紐約高中的比賽多半都要付錢進去看。今年開始,學校恢復正常,比賽活動就可以進場看。賽季的比賽都在平日4,5點,看孩子打球的機會不大。 紐約市來說,Brooklyn的球隊比較強。我們在Qu