Golang : How to handle file size larger than available memory panic issue
Problem:
You are trying to convert create a slice with a size of a very large file. The file size is larger than available memory and it caused your Golang program to panic during runtime. How to overcome this panic issue?
Solution:
It was once thought that 640KB of memory should be enough for all our computing needs, but that is no longer true. However, hitting a memory limit issue will always be there. Hence the solution is:
Get the available memory first before creating the slice.
If the file size is lower than the available memory than proceed as usual. However, if the file size is larger than available memory, chunk the file according to a sensible size and process each chunks without bursting the total available memory.
package main
import (
"fmt"
"net/http"
"os"
"github.com/shirou/gopsutil/mem"
)
func main() {
// memory
vmStat, err := mem.VirtualMemory()
if err != nil {
panic(err)
}
availableMemory := vmStat.Available
//availableMemory := uint64(655360) // uncomment to test low memory situation
fmt.Println("Available memory : ", availableMemory, " bytes")
fileToBeUploaded := "somebigfile"
file, err := os.Open(fileToBeUploaded)
if err != nil {
panic(err)
}
defer file.Close()
fileInfo, _ := file.Stat()
fileSize := uint64(fileInfo.Size())
fmt.Println("File size : ", fileSize, " bytes")
// previous tutorials did not check if the fileSize is larger than
// available memory. However, bear in mind that
// http.DetectContentType() only needs 512 bytes, not the entire file
if fileSize < availableMemory {
fileBytes := make([]byte, fileSize)
fmt.Println("File converted into []byte")
fileType := http.DetectContentType(fileBytes)
fmt.Println("File type : ", fileType)
} else {
// see https://golang.org/pkg/net/http/#DetectContentType
fmt.Println("Not enough memory to read the entire file into []byte!")
fileBytes := make([]byte, 512) // we only need 512 bytes
fileType := http.DetectContentType(fileBytes)
fmt.Println("File type : ", fileType)
}
// However, if http.DetectContentType() is not your concern then you will need to
// split the file to smaller pieces within the available memory and process it
// without causing panic
// such as
// https://www.socketloop.com/tutorials/golang-how-to-split-or-chunking-a-file-to-smaller-pieces
// https://www.socketloop.com/tutorials/golang-upload-big-file-larger-than-100mb-to-aws-s3-with-multipart-upload
// calculate the number of parts by dividing up the file size by 5MB
const fileChunk = 5242880 // 5MB in bytes
// or
const fileChunk = availableMemory - 10000 // not wise to use up all availableMemory, tweak around figure to minus!
}
See also : Golang : Get hardware information such as disk, memory and CPU usage
By Adam Ng(黃武俊)
IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.
Advertisement
Tutorials
+4.1k Golang : Converting individual Jawi alphabet to Rumi(Romanized) alphabet example
+6.4k Golang : Totalize or add-up an array or slice example
+5.5k Golang : ROT32768 (rotate by 0x80) UTF-8 strings example
+12.9k Golang : Skip blank/empty lines in CSV file and trim whitespaces example
+8.3k Golang : How to check if input string is a word?
+6.7k Golang : How to solve "too many .rsrc sections" error?
+20.9k Golang : Sort and reverse sort a slice of strings
+9k Android Studio : Indicate progression with ProgressBar example
+5k Golang : Convert lines of string into list for delete and insert operation
+8.6k Android Studio : Image button and button example
+11.7k Golang : How to parse plain email text and process email header?
+18.2k Golang : Logging with logrus