1. 内存泄露
内存泄露指程序未能释放不再使用的内存,导致内存占用持续增长。
解决流程:
(1)监控与定位:
-
使用工具监控内存(如Python的tracemalloc,Java的VisualVM)
-
观察内存增长曲线,定位可疑代码段
import tracemalloc
tracemalloc.start() # 开始监控
# ...执行可疑代码...
snapshot = tracemalloc.take_snapshot() # 快照
top_stats = snapshot.statistics('lineno') # 按行统计
for stat in top_stats[:10]: # 打印前10个泄露点
print(stat)
(2)常见泄露场景:
-
未释放资源:文件/网络连接未关闭
-
全局集合:全局字典/列表持续添加数据
-
循环引用:对象互相引用(Python需用gc模块解决)
-
监听器未移除:事件监听器未注销
(3)修复策略:
-
使用try-finally或with确保资源释放
-
弱引用(weakref)解决循环引用
-
定期清理缓存(如LRU策略)
2. MySQL排名函数
2.1 ROW_NUMBER()
连续唯一排名(无重复值):
SELECT name, score,
ROW_NUMBER() OVER (ORDER BY score DESC) AS rank
FROM students;
2.2 RANK()
允许并列排名(跳跃编号):
SELECT name, score,
RANK() OVER (ORDER BY score DESC) AS rank
FROM students;
2.3 DENSE_RANK()
允许并列且连续排名:
SELECT name, score,
DENSE_RANK() OVER (ORDER BY score DESC) AS rank
FROM students;
3. 死锁
多个进程互相持有对方所需资源,导致永久阻塞。需满足四个条件:
-
互斥访问
-
持有并等待
-
不可剥夺
-
循环等待
真实案例:银行转账
事务A:
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- 锁住账户1
UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- 请求账户2的锁
COMMIT;
事务B(反向操作):
START TRANSACTION;
UPDATE accounts SET balance = balance - 50 WHERE id = 2; -- 锁住账户2
UPDATE accounts SET balance = balance + 50 WHERE id = 1; -- 请求账户1的锁
COMMIT; -- 互相等待导致死锁
解决方案:
-
重试机制:捕获死锁错误(MySQL错误码1213),延迟后重试
-
统一加锁顺序:所有事务按固定顺序操作资源(如先操作id小的账户)
-
设置超时:innodb_lock_wait_timeout=50(单位:秒)
-
减少事务粒度:避免长事务
4. 主键和外键
二者的区别如下:
特性 | 主键 (Primary Key) | 外键 (Foreign Key) |
---|---|---|
唯一性 | 唯一标识每行记录 | 可重复(指向其他表主键) |
空值 | 不允许NULL | 允许NULL |
数量限制 | 每表仅一个 | 每表可多个 |
作用 | 数据唯一性约束 | 维护表间引用完整性 |
索引 | 自动创建唯一索引 | 需手动创建索引 |
外键使用案例如下:
CREATE TABLE Orders (
order_id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id) REFERENCES Users(user_id)
ON DELETE CASCADE -- 用户删除时自动删除其订单
);