Nginx内存池
概念直接使用 malloc 分配内存,由于每次分配的块大小不一,容易造成内存碎片化,当需要大块内存时,就可能找不到连续的大块空闲内存空间了,同时也会一定程度影响性能。内存池 就是预先分配一组固定大小的内存块然后自行管理内存的分配和释放,从而提高内存分配效率。以下剖析 Nginx 的内存池,源码版本 1.24.0
Nginx 内存池设计
内存分配尽量对齐,以提高 CPU 的访问效率
小块内存分配从已有块中提取,大块内存直接 malloc
小块内存只有在销毁内存池时才统一释放
1. 内存对齐宏#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
#define ngx_align_ptr(p, a) \
(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
表示得出按 a 对齐的结果,a 必须是 ...
Using Asio with C++11
原文链接:《Using Asio with C++11》
本文既是对Asio库的介绍,也是对其实现和与C++11结合使用的简要概述。
1. Asio 库的 C++11 变体本文不是使用 Asio 库的 Boost 发行版,而是一个独立于 Boost 的 Asio 变体。此变体的目标包括:
在接口中只使用 C++11 语言特性;
证明该库可以仅使用C++11标准库和操作系统提供的设施来实现。
这个变体的仓库地址在 https://github.com/chriskohlhoff/asio/tree/cpp11-only
2. 使用 I/O 流解决一些简单问题的用例在许多应用程序中,网络不是一个核心功能,也不被视为应用程序开发者的核心能力。为了迎合这些用例,Asio 提供了一个高级的 TCP 套接字接口,它是围绕我们熟悉的 C++ I/O 流框架设计的。
使用这个库可以通过下面这种方式用远程主机的详细信息轻易地构造一个流对象:
asio::ip::tcp::iostream s("www.boost.org", "http");
接下来,决定是 ...
Oracle笔记
Oracle 笔记1. 用户相关操作
查看当前用户
show user;
/* 或 */
select user from dual;
查看所有用户名
select * from all_users;
创建新用户
sqlplus /nolog /* 进入 sqlplus 环境, nolog 参数表示不登录 */
sqlplus /as sysdba /* 以系统管理员身份登录 */
sqlplus (用户名)/密码 /* 登录一般用户 */
create user xixi identified by mima; /* 创建用户 xixi, 密码为 mima */
给用户授予权限
GRANT CREATE USER,DROP USER,ALTER USER ,CREATE ANY VIEW , DROP ANY VIEW,EXP_FULL_DATABASE,IMP_FULL_DATABASE, DBA, CONNECT,RESOURCE,CREATE SESSION TO
xixi;
切换新用户
conn(ect) xixi/mima;
删除用户
drop user xixi;
/ ...
gdb笔记
GDB 笔记1. 启动 GDB
gdb <program>:programe 即可执行文件,一般在当前目录下
gdb <program> core :用 gdb 同时调试一个运行程序和 core 文件,core 是程序非法执行后 core dump 后产生的文件,这个文件名也可以自己规定(见后文)
gdb <program> <PID> :让 gdb 调试器附着到一个正在运行的进程上,program 应该在 PATH 环境变量中搜索得到
# 例如 a.out 为一个正在运行的程序, 其 PID 为 15344
# 则可以让 gdb 附着在其上
(gdb) gdb a.out 15344
# 如果不想继续调试了, 可以使用 detach 命令脱离进程
(gdb) detach
2. 暂停机制
断点:通知 GDB 在程序中的特定位置暂停执行
监视点:通知 GDB 当特定内存位置(或者涉及一个或多个位置的表达式)的值发生变化时暂停执行
捕获点:通知 GDB 当特定事件发生时暂停执行
2.1 设置断点
break function
(g ...
网络编程笔记
网络编程IPv4 套接字地址结构它以 sockaddr_in 命名,定义在 <netinet/in.h> 头文件中,POSIX 定义如下:
struct in_addr {
in_addr_t s_addr; /* 32-bit IPv4 address */
};
struct sockaddr_in {
uint8_t sin_len;
sa_family_t sin_family; /* AF_INET */
in_port_t sin_port; /* 16-bit TCP or UDP port number */
struct in_addr sin_addr; /* 32-bit IPv4 address */
char sin_zero[8]; /* unused */
};
POSIX 规范只需要这个结构中的3个字段:sin_family 、sin_addr 和 sin_port 。
sin_zero 字段未曾使用,不过在填写这种套接字地址结构时,我们 ...
MySQL笔记
MySQL 笔记1. 数据库操作# 创建数据库
CREATE DATABASE MySQL;
# 选择数据库
USE MySQL;
# 查看数据库
SHOW DATABASES;
# 查看当前数据库的表
SHOW TABLES;
# 显示创建特定数据库或表的语句
SHOW CREATE DATABASE MySQL;
SHOW CREATE TABLE tb;
# 显示授予用户的安全权限
SHOW GRANTS;
# 显示服务器错误或警告消息
SHOW ERRORS;
SHOW WARNINGS;
2. 表操作2.1 创建和操纵表# 创建表 (IF NOT EXISTS 会先检查是否有重复表名)
CREATE TABLE IF NOT EXISTS customers
(
cust_id int NOT NULL AUTO_INCREMENT, # 每个表只允许一个 AUTO_INCREMENT
cust_name char(50) NOT NULL ,
cust_address char(50) NULL ,
cust ...
操作系统笔记(14)-常见并发问题
操作系统笔记(14)-常见并发问题简介
常见的并发程序缺陷主要有两种:非死锁缺陷 和 死锁缺陷
非死锁缺陷
非死锁缺陷主要又分为两种:违反原子性缺陷 和 错误顺序缺陷
违反原子性缺陷
违反原子性的定义是:违反了多次内存访问中预期的可串行性(即代码段本意是原子的,但是在执行中并没有强制实现原子性)
T0:
if (ptr != NULL) {
doSomething(ptr);
}
T1:
ptr = NULL;
若线程 T0 正要执行 doSomething 之前切换到 T1 执行,将 ptr 置为 NULL ,再切回 T0 会导致程序崩溃
解决方法 : 在代码前后添加互斥锁,避免线程切换
违反顺序缺陷
违反顺序的定义是:两个内存访问的预期顺序打破了(即 A 应该在 B 之前执行,但是实际运行中却不是这个顺序)
T0:
void init() {
ptr = CreatePtr(mMain, ...);
}
T1:
void mMain(...) ...
操作系统笔记(13)-信号量
操作系统笔记(13)-信号量简介
信号量是另一种提供线程同步的方式,可以使用信号量作为锁和条件变量
POSIX 信号量 API#include <semaphore.h>
// 初始化信号量
// 1. sem_t 变量
// 2. pshared 为0表示这个信号量是当前进程的局部信号量, 否则该信号量可以在多个进程之间共享
// 3. value 指定信号量初始值
int sem_init(sem_t* sem, int pshared, unsigned int value);
// 销毁信号量
int sem_destroy(sem_t* sem);
// 以原子操作的方式将信号量的值减一。 减完后信号量的值若小于0,就等待至信号量大于等于0
int sem_wait(sem_t* sem);
// 始终立即返回, 当信号量为0时返回-1并设置errno
int sem_trywait(sem_t* sem);
// 原子地将信号量加一
int sem_post(sem_t* sem);
信号量充当互斥锁
将信号量的初始值设置为 1 即可
#include ...
操作系统笔记(12)-条件变量
操作系统笔记(12)-条件变量简介
在很多情况下,线程需要检查某一条件满足之后,才会继续运行,比如说主线程可以等待子线程执行完后再继续执行
条件变量可以令线程在条件 未满足 时进入 睡眠 ,也支持在任务完成后 唤醒 另外的线程
pthread_cond_wait 调用之前必须持有锁,因为它会释放锁然后使线程进入 cond 等待队列,当使用 pthread_cond_signal 或 pthread_cond_broadcast 时,会将线程从 cond 队列移动到 mutex 队列,再次获取锁后执行相关任务
父线程等待子线程:使用条件变量
利用 条件变量 实现父线程等待子线程
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
int done = 0;
// 另一种初始化的方式
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
pthread_mutex_t m = PTHREAD_MUTEX_IN ...
操作系统笔记(11)-锁
操作系统笔记(11)-锁简介
上一个笔记介绍了 POSIX 提供的互斥锁 API ,我们知道了在进入临界区前加锁,能够保证临界区能够像单条原子指令一样执行
评价锁评价一个锁主要从三个方面来看:
提供互斥 :锁需要提供的最基本功能
公平性 :确保每一个竞争线程有公平的机会获得锁
性能 :使用锁之后的性能如何(在各种环境下)
实现一个锁测试并设置指令(原子交换)
早期由硬件支持的 原子 交换指令,即 测试并设置(test-and-set) ,它的逻辑实现如下:
// 硬件保证此操作是原子的, x86 为 xchg 指令
int TestAndSet(int *old_ptr, int new_value) {
int old = *old_ptr;
*old_ptr = new_value;
return old;
}
实现一个 自旋锁
typedef struct lock_t {
int flag;
} lock_t;
void init(lock_t *lock) {
lo ...