Funplus 服务端开发实习 面经
redis zset说说底层
如果要你自己实现一个简单缓存怎么做
缓存淘汰应该有哪些策略
Redis
Mysql Buffer Pool
golang gc
什么是混合写屏障
混合写屏障(Hybrid Write Barrier)是 Golang 在 1.8 版本中引入的一种机制,旨在优化垃圾回收(GC)过程。它通过结合插入写屏障和删除写屏障的特点,减少了标记阶段的停顿时间(STW,Stop The World),从而提高了程序的并发性能。
实现机制
插入写屏障:在对象引用时,将新创建的对象标记为灰色,以防止黑色对象引用白色对象。这一机制确保了在并发环境中,引用关系的正确性。(不适用于栈区)
删除写屏障:在删除引用时,如果被删除的对象是灰色或白色,则将其标记为灰色,以保持灰色对象到白色对象的路径不被断开。
混合机制:在 GC 开始时,栈上的可达对象会被标记为黑色,任何在栈上新创建的对象也会被标记为黑色。这种方式避免了对栈的重复扫描,从而减少了 STW 的时间。
声明变量什么时候在栈里什么时候在堆里
在编程中,变量的存储位置(栈或堆)由变量的生命周期、作用域和编程语言的特性共同决定。以下是核心原则和常见场景:
一、栈(Stack)与堆(Heap)的核心区别
特性 | 栈(Stack) | 堆(Heap) |
---|---|---|
分配方式 | 自动分配/释放(编译器管理) | 手动分配/释放(开发者或GC管理) |
速度 | 极快(指针移动即可分配) | 较慢(需搜索可用内存块) |
生命周期 | 随函数调用结束自动释放 | 可长期存在(需显式释放或GC回收) |
碎片化 | 无碎片(后进先出) | 可能产生内存碎片 |
典型用途 | 局部变量、函数参数、返回值 | 动态分配的对象、大块数据 |
二、变量何时分配在栈中?
1. 局部变量(基本类型)
void func() {int a = 10; // 栈中(自动分配)char c = 'x'; // 栈中
}
- 条件:变量在函数内声明,且为基本类型(如
int
,float
)。 - 生命周期:函数结束时自动释放。
2. 函数调用上下文
int add(int x, int y) { // 参数x、y在栈中return x + y; // 返回值可能通过栈传递
}
- 条件:函数参数、返回地址、寄存器保存值等。
3. 小对象(某些语言优化)
func main() {p := struct{ x int }{x: 10} // Go中可能直接在栈分配
}
- 条件:某些语言(如Go、Rust)对小对象或短生命周期对象进行栈分配优化。
三、变量何时分配在堆中?
1. 显式动态分配
int* p = malloc(sizeof(int)); // C中堆分配
*p = 10;
- 条件:使用
malloc
(C)、new
(C++/Java)等显式操作。
2. 对象或引用类型
void func() {Object obj = new Object(); // Java对象在堆中
}
- 条件:在面向对象语言(Java/C#/Python)中,对象通常分配在堆中,变量(如
obj
)仅存储堆地址。
3. 逃逸分析(Escape Analysis)
func foo() *int {x := 42 // Go编译器可能将x分配在堆(因逃逸到函数外)return &x
}
- 条件:变量被外部引用(如返回指针、闭包捕获),编译器可能强制堆分配。
4. 大块内存(避免栈溢出)
void func() {int bigArray[1000000]; // 大数组可能导致栈溢出(需改用堆)
}
- 条件:栈空间有限(通常MB级),超大变量需用堆(如
new int[1000000]
)。
四、不同语言的典型行为
语言 | 栈分配 | 堆分配 |
---|---|---|
C/C++ | 局部变量、数组、结构体 | malloc /new 显式分配 |
Java | 基本类型(int , char ) | 对象(new 创建)、容器类 |
Python | 无显式栈/堆区分(一切皆对象,由解释器管理) | |
Go | 小对象、未逃逸变量(编译器优化) | 显式逃逸的对象、new 或 make 创建 |
Rust | 默认栈分配,需显式使用 Box 堆分配 | Box::new() 或集合类型 |
五、如何判断变量在栈还是堆?
-
C/C++:
- 栈:局部变量、函数参数。
- 堆:
malloc
/new
分配的内存。
int* p = (int*)malloc(sizeof(int)); // p在栈,*p在堆
-
Java:
- 栈:基本类型变量(如
int a = 10;
)。 - 堆:对象实例(
String s = new String();
)。
- 栈:基本类型变量(如
-
Go:
- 通过逃逸分析决定:
go build -gcflags="-m" # 查看变量逃逸分析结果
- 通过逃逸分析决定:
六、关键总结
- 栈:自动管理、高效、短生命周期。
- 堆:手动或GC管理、灵活、长生命周期。
- 核心原则:
- 如果变量生命周期不超过函数作用域,优先栈分配。
- 如果变量需跨作用域共享或占用内存过大,必须堆分配。
理解这一点,可以更好地优化内存使用(如避免不必要的堆分配)并防止内存泄漏。
git merge和rebase有什么区别吗
参考:https://zhuanlan.zhihu.com/p/686538265