From df18e1a4bd11a09f081eea5e01eaea01302c94fb Mon Sep 17 00:00:00 2001 From: Inanc Gumus Date: Sun, 18 Aug 2019 13:29:12 +0300 Subject: [PATCH] refactor: slices 24th exercise --- .../24-fix-the-memory-leak/api/api.go | 18 +++++++- .../exercises/24-fix-the-memory-leak/main.go | 45 ++++++++++++------- .../solution/api/api.go | 18 +++++++- .../24-fix-the-memory-leak/solution/main.go | 29 ++++++++---- 4 files changed, 81 insertions(+), 29 deletions(-) diff --git a/16-slices/exercises/24-fix-the-memory-leak/api/api.go b/16-slices/exercises/24-fix-the-memory-leak/api/api.go index aa715e0..7798f03 100644 --- a/16-slices/exercises/24-fix-the-memory-leak/api/api.go +++ b/16-slices/exercises/24-fix-the-memory-leak/api/api.go @@ -7,15 +7,29 @@ import ( ) // DO NOT TOUCH THE FOLLOWING CODE -// THIS IS THE API -// YOU CANNOT CONTROL IT! :) +// THIS IS THE IMAGINARY API CODE +// YOU CANNOT CONTROL IT! // Read returns a huge slice (allocates ~65 MB of memory) func Read() []int { + // 2 << 22 means 2^(22 + 1) + // See this: https://en.wikipedia.org/wiki/Arithmetic_shift + + // Perm function returns a slice with random integers in it. + // Here it returns a slice with random integers that contains + // 8,388,608 elements. One int value is 8 bytes. + // So: 8,388,608 * 8 = ~65MB return rand.Perm(2 << 22) } // Report cleans the memory and prints the current memory usage +// Don't worry about this code. You don't need to understand it. +// +// However, if you're curious, read on. +// +// The following code runs the garbage collector to clean +// up the allocated resources, and then it reads the current +// memory statistics into the m variable. func Report() { var m runtime.MemStats runtime.GC() diff --git a/16-slices/exercises/24-fix-the-memory-leak/main.go b/16-slices/exercises/24-fix-the-memory-leak/main.go index 92cdbf7..cfcdd0f 100644 --- a/16-slices/exercises/24-fix-the-memory-leak/main.go +++ b/16-slices/exercises/24-fix-the-memory-leak/main.go @@ -17,11 +17,25 @@ import ( // --------------------------------------------------------- // EXERCISE: Fix the memory leak // -// You receive millions of temperature data points from -// an API, but you only need the last 10 data points. +// WARNING! This is a very difficult exercise. You need to +// do some research on your own to solve it. Please don't +// get discouraged if you can't solve it yet. // -// Currently, there is a memory leak in your program. -// Find the leak and fix it. +// Imagine that you receive millions of temperature data +// points but you only need the last 10 data points +// (temperatures). +// +// Problem: There is a memory leak in your program. +// Please find the leak and fix it. +// +// Memory leak means: Your program uses computer memory +// unnecessarily. See this: https://en.wikipedia.org/wiki/Memory_leak +// +// +// CURRENT OUTPUT +// +// > Memory Usage: 113 KB +// > Memory Usage: 65651 KB // // // EXPECTED OUTPUT @@ -32,16 +46,14 @@ import ( // // EXPECTED OUTPUT EXPLANATION // -// Your output will be different. Your goal is to reduce the -// difference between two measurements of the memory usage. -// -// For the expected output above: -// -// 118 KB - 116 KB = Only 2 KB so that's OK. -// -// However, in the current program, because of the memory leak, +// In the current program, because of the memory leak, // the difference is huge: about ~60 MB. Run the program and, -// see yourself. +// see it yourself. +// +// Your goal is reducing the memory usage. +// +// See the code in api/api.go to see how it allocates +// a huge memory. // // --------------------------------------------------------- @@ -49,7 +61,7 @@ func main() { // reports the initial memory usage api.Report() - // reads 65 MB of temperature data into the memory! + // reads 65 MB of temperature data into memory! temps := api.Read() // ----------------------------------------------------- @@ -60,8 +72,9 @@ func main() { // ✪ ONLY ADD YOUR CODE INSIDE THIS BOX ✪ // ----------------------------------------------------- - // fix the problem so that the memory usage stays low - // dont touch this code + // dont touch this code. api.Report() + + // don't worry about this code yet. fmt.Fprintln(ioutil.Discard, temps[0]) } diff --git a/16-slices/exercises/24-fix-the-memory-leak/solution/api/api.go b/16-slices/exercises/24-fix-the-memory-leak/solution/api/api.go index aa715e0..7798f03 100644 --- a/16-slices/exercises/24-fix-the-memory-leak/solution/api/api.go +++ b/16-slices/exercises/24-fix-the-memory-leak/solution/api/api.go @@ -7,15 +7,29 @@ import ( ) // DO NOT TOUCH THE FOLLOWING CODE -// THIS IS THE API -// YOU CANNOT CONTROL IT! :) +// THIS IS THE IMAGINARY API CODE +// YOU CANNOT CONTROL IT! // Read returns a huge slice (allocates ~65 MB of memory) func Read() []int { + // 2 << 22 means 2^(22 + 1) + // See this: https://en.wikipedia.org/wiki/Arithmetic_shift + + // Perm function returns a slice with random integers in it. + // Here it returns a slice with random integers that contains + // 8,388,608 elements. One int value is 8 bytes. + // So: 8,388,608 * 8 = ~65MB return rand.Perm(2 << 22) } // Report cleans the memory and prints the current memory usage +// Don't worry about this code. You don't need to understand it. +// +// However, if you're curious, read on. +// +// The following code runs the garbage collector to clean +// up the allocated resources, and then it reads the current +// memory statistics into the m variable. func Report() { var m runtime.MemStats runtime.GC() diff --git a/16-slices/exercises/24-fix-the-memory-leak/solution/main.go b/16-slices/exercises/24-fix-the-memory-leak/solution/main.go index c2885af..97bccac 100644 --- a/16-slices/exercises/24-fix-the-memory-leak/solution/main.go +++ b/16-slices/exercises/24-fix-the-memory-leak/solution/main.go @@ -21,25 +21,36 @@ func main() { // reads 65 MB of temperature data into the memory! temps := api.Read() - // + // ------------------------------------------------------ // SOLUTION #1: - // + // ------------------------------------------------------ - // clone the last 10 elements of the returned temperatures - // into a new slice + // + // Copy the last 10 elements of the returned temperatures + // to a new slice. + // + // This will create a new backing array. + // need := make([]int, 10) copy(need, temps[len(temps)-10:]) - // make the temp slice lose reference to its backing array - // so that it can be cleaned from the memory + + // + // Make the temp slice lose reference to its backing array + // so that its backing array can be cleaned from the memory. + // temps = need - // + // ------------------------------------------------------ // SOLUTION #2: - // + // ------------------------------------------------------ + + // Similar to the 1st solution. It does the same thing. + // But this code is more concise. Use this one. - // The code below does the same thing like the code above but in one line. // temps = append([]int(nil), temps[len(temps)-10:]...) + // ------------------------------------------------------ + // don't worry about this code yet. api.Report() fmt.Fprintln(ioutil.Discard, temps[0]) }