GO开发:GIN面试题


GO开发:GIN面试题

文章插图
 
Go语言面试问得最多的面试题new 和 make 的区别【GO开发:GIN面试题】首先我们得知道 , Go分为数据类型分为值类型和引用类型 , 其中
值类型是 int、float、string、bool、struct和array , 它们直接存储值 , 分配栈的内存空间 , 它们被函数调用完之后会释放
引用类型是 slice、map、chan和值类型对应的指针 它们存储是一个地址(或者理解为指针),指针指向内存中真正存储数据的首地址 , 内存通常在堆分配 , 通过GC回收
区别new 的参数要求传入一个类型 , 而不是一个值 , 它会申请该类型的内存大小空间 , 并初始化为对应的零值 , 返回该指向类型空间的一个指针
make 也用于内存分配 , 但它只用于引用对象 slice、map、channel的内存创建 , 返回的类型是类型本身
值传递和指针传递有什么区别值传递:会创建一个新的副本并将其传递给所调用函数或方法 指针传递:将创建相同内存地址的新副本
需要改变传入参数本身的时候用指针传递 , 否则值传递
另外 , 如果函数内部返回指针 , 会发生内存逃逸
聊聊内存逃逸分析Go的逃逸分析是一种确定指针动态范围的方法 , 可以分析程序在哪些可以访问到指针 , 它涉及到指针分析和状态分析 。
当一个变量(或对象)在子程序中被分配时 , 一个指向变量的指针可能逃逸到其它程序 , 或者去调用子程序 。 如果使用尾递归优化(通常函数式编程是需要的) , 对象也可能逃逸到被调用程序中 。如果一个子程序分配一个对象并返回一个该对象的指针 , 该对象可能在程序中的任何一个地方都可以访问 。
如果指针存储在全局变量或者其它数据结构中 , 它们也可能发生逃逸 , 这种情况就是当前程序的指针逃逸 。逃逸分析需要确定指针所有可以存储的地方 , 保证指针的生命周期只在当前进程或线程中 。
导致内存逃逸的情况比较多(有些可能官方未能够实现精确的逃逸分析情况的bug) , 通常来讲就是如果变量的作用域不会扩大并且行为或者大小能够在其编译时确定 , 一般情况下都分配栈上 , 否则就可能发生内存逃逸到堆上 。
引用内存逃逸的典型情况: * 在函数内部返回把局部变量指针返回 局部变量原本应该在栈中分配 , 在栈中回收 。但是由于返回时被外部引用 , 因此生命周期大于栈 , 则溢出
  • 发送指针或带有指针的值到channel中 在编译时 , 是没办法知道哪个 goroutine 会在 channel上接受数据 , 所以编译器没办法知道变量什么时候释放 。
  • 在一个切片上存储指针或带指针的值 一个典型的例子就是 []*string , 这会导致切片的内容逃逸 , 尽管其后面的数组在栈上分配 , 但其引用值一定是在堆上
  • slice 的背后数组被重新分配了 因为 Append 时可能会超出其容量( cap ) 。slice 初始化的地方在编译时是可以知道的 , 它最开始会在栈上分配 。如果切片背后的存储要基于运行时的数据进行扩充 , 就会在堆上分配 。
  • 在 interface 类型上调用方法 在 interface 类型上调用方法都是动态调度的 —— 方法的真正实现只能在运行时知道 。想像一个 io.Reader 类型的变量 r , 调用 r.Read(b) 会使得 r 的值和切片b 的背后存储都逃逸掉 , 所以会在堆上分配 。
了解过golang的内存管理吗内存池概述Go语言的内存分配器采用了跟 tcmalloc 库相同的实现 , 是一个带内存池的分配器 , 底层直接调用操作系统的 mmpa 等函数 。
作为一个内存池 , 它的基本部分包括以下几部分: