1.开源项目|高性能内存分配库mimalloc
2.ä¼åmysql å¤å¤§å
å centos6
3.在英特尔 CPU 上微调 Stable Diffusion 模型
4.Spring Boot引起的源码“堆外内存泄漏”排查及经验总结
开源项目|高性能内存分配库mimalloc
mimalloc
开源内存分配库,微软研究院年发布,源码旨在提供高性能内存管理解决方案。源码
使用方法如下:
1. 克隆代码库至本地。源码
2. 编译代码。源码
3. 将头文件复制至系统目录,源码iapp免费源码大师如:
4. 编译项目时链接mimalloc。源码
尝试直接使用mimalloc,源码无需编译:
配置环境变量。源码
mimalloc特点:
1. 简洁高效,源码核心代码量少于行。源码
2. 性能显著优于其他内存分配库,源码如:mi(mimalloc)、源码tc(tcmalloc)、源码je(jemalloc)等。源码
3. 支持多线程。
架构:
mimalloc设计中,每个线程拥有专属堆,线程在分配内存时从各自堆进行。堆中包含多个分段,每个分段对应多个页面,内存分配在页面上进行。
free列表操作代码。
源码实现:
1. malloc函数实现
2. free函数实现
参考资料:
[1] cnblogs.com/linkwk7/p/1...
[2] github.com/microsoft/mi...
[3] cnblogs.com/linkwk7/p/1...
ä¼åmysql å¤å¤§å å centos6
ä¸ãmysqlçä¼åæè·¯
mysqlçä¼åå为两æ¹é¢ï¼
1. æå¡å¨ä½¿ç¨åçä¼å
2. æå¡ä½¿ç¨ä¸çä¼å
äºãmysqlçåºç¡ä¼åæ¥éª¤
1. 硬件级ä¼å
ï¼1ï¼. æ好mysqlèªå·±ä½¿ç¨ä¸å°ç©çæå¡å¨
ï¼2ï¼. å ååCPUæ¹é¢ï¼æ ¹æ®éæ±ç»äºmysqlæå¡å¨è¶³å¤å¤§çå åå足å¤å¤çCPUæ ¸æ°
(3). é¿å 使ç¨Swap交æ¢ååºâ交æ¢æ¶ä»ç¡¬ç读åçå®çé度å¾æ ¢ï¼æçDBAå®è£ ç³»ç»æ¶å°±ä¸è£ swapååº
ï¼4ï¼. å¦ææ¯mysql主åºï¼ç¡¬çå¯ä»¥éç¨æ¯è¾å¥½çé«é硬çï¼ç³»ç»ç¨SSDåºæ硬çï¼æ°æ®çç¨sasæ¿ä»£sata硬çï¼å°æä½ç³»ç»åæ°æ®ååºåå¼
ï¼5ï¼. mysql产ççæ¥å¿ä¸æ°æ®åºä¹æ¾å°ä¸åçç£çååºä¸é¢
ï¼6ï¼. mysqlæ°æ®åºç¡¬çæ ¼å¼åæ¶ï¼å¯ä»¥æå®æ´å°ç硬çå
ï¼7ï¼. å ³äºåRAIDæ¹é¢ï¼ä¸»åºå°½éåæRAIDï¼æ¢æé«äºæ°æ®ç读åé度ä¹æå°äºæ°æ®çå®å ¨æ§
ï¼8). æå¡å¨å线åçµï¼ä¿éæå¡å¨è¿è¡ç¨³å®ï¼ä¸ä¼å 为çªç¶æçµå½±åä¸å¡åæåç£çæ°æ®
2. mysqlæ°æ®åºè®¾è®¡ä¼å
ï¼1). æ ¹æ®éæ±éæ©æ£ç¡®çåå¨å¼æï¼æ¯å¦è¯´è¯»çç¹å«çå°±ç¨MySAM,å¦æ对äºå¡æ§è¦æ±é«å°±ç¨InnoDB
(2). 设置åççå段类ååå段é¿åº¦,æ¯å¦è¯´ä½ è¿ä¸ªå段就å¤ä¸ªåæ®µä½ è®¾ç½®æVARCHAR()å°±æ¯å¯¹ç£ç空é´ç浪费
ï¼3ï¼. é»è®¤å¼å°½å¯è½çä½¿ç¨ NOT NULLï¼å¦æ空å¼å¤ªå¤å¯¹mysqlçæ¥è¯¢ä¼æå½±åï¼å°¤å ¶æ¯å¨æ¥è¯¢è¯å¥ç¼åä¸é¢
ï¼4ï¼. å°½éå°ç使ç¨VARCHARï¼TEXTï¼BLOBè¿ä¸ä¸ªå段
ï¼5ï¼. æ·»å éå½ç´¢å¼(index) [åç§: æ®éç´¢å¼ã主é®ç´¢å¼ãå¯ä¸ç´¢å¼uniqueãå ¨æç´¢å¼]
ï¼6ï¼. ä¸è¦æ»¥ç¨ç´¢å¼ï¼å¤§è¡¨ç´¢å¼ï¼å°è¡¨ä¸ç´¢å¼
ï¼7ï¼. 表ç设计åçå(符å3NF)
3. mysqlé ç½®åæ°çä¼å
è¿éæ¯mysql5.5çæ¬çé ç½®æ件
vi my.cnf
[client]
port = #mysql客æ·ç«¯è¿æ¥æ¶çé»è®¤ç«¯å£
socket = /tmp/mysql.sock #ä¸mysqlæå¡å¨æ¬å°éä¿¡æ使ç¨çsocketæ件路å¾
default-character-set = utf8 #æå®é»è®¤å符é为utf8
[mysql]
no-auto-rehash #auto-rehashæ¯èªå¨è¡¥å ¨çææï¼å°±åæ们å¨linuxå½ä»¤è¡éè¾å ¥å½ä»¤çæ¶åï¼ä½¿ç¨tabé®çåè½æ¯ä¸æ ·çï¼è¿éæ¯é»è®¤çä¸èªå¨è¡¥å ¨
default-character-set = utf8 #æå®é»è®¤å符é为utf8
[mysqld]
user = mysql
port =
character-set-server = utf8 #设置æå¡å¨ç«¯çå符ç¼ç
socket = /tmp/mysql.sock
basedir = /application/mysql
datadir = /mysqldata
skip-locking #é¿å MySQLçå¤é¨éå®ï¼åå°åºéå çå¢å¼ºç¨³å®æ§ã
open_files_limit = #MySQLæå¼çæ件æ述符éå¶ï¼é»è®¤æå°;å½open_files_limit没æ被é ç½®çæ¶åï¼æ¯è¾max_connections*5åulimit -nçå¼ï¼åªä¸ªå¤§ç¨åªä¸ªï¼å½open_file_limit被é ç½®çæ¶åï¼æ¯è¾open_files_limitåmax_connections*5çå¼ï¼åªä¸ªå¤§ç¨åªä¸ªã
back_log = #back_logåæ°çå¼æåºå¨MySQLææ¶åæ¢ååºæ°è¯·æ±ä¹åççæ¶é´å å¤å°ä¸ªè¯·æ±å¯ 以被åå¨å æ ä¸ã å¦æç³»ç»å¨ä¸ä¸ªçæ¶é´å æå¾å¤è¿æ¥ï¼åéè¦å¢å¤§è¯¥åæ°çå¼ï¼è¯¥åæ°å¼æå®å°æ¥çTCP/IPè¿æ¥ç侦å¬éåç大å°ãä¸åçæä½ç³»ç»å¨è¿ä¸ªéå大å°ä¸æå®èª å·±çéå¶ã è¯å¾è®¾back_logé«äºä½ çæä½ç³»ç»çéå¶å°æ¯æ æçãé»è®¤å¼ä¸ºã对äºLinuxç³»ç»æ¨è设置为å°äºçæ´æ°ã
max_connections = #MySQLçæ大è¿æ¥æ°ï¼å¦ææå¡å¨ç并åè¿æ¥è¯·æ±éæ¯è¾å¤§ï¼å»ºè®®è°é«æ¤å¼ï¼ä»¥å¢å 并è¡è¿æ¥æ°éï¼å½ç¶è¿å»ºç«å¨æºå¨è½æ¯æçæ åµä¸ï¼å 为å¦æè¿æ¥æ°è¶å¤ï¼ ä»äºMySQLä¼ä¸ºæ¯ä¸ªè¿æ¥æä¾è¿æ¥ç¼å²åºï¼å°±ä¼å¼éè¶å¤çå åï¼æ以è¦éå½è°æ´è¯¥å¼ï¼ä¸è½ç²ç®æé«è®¾å¼ãå¯ä»¥è¿âconn%âéé 符æ¥çå½åç¶æçè¿æ¥ æ°éï¼ä»¥å®å¤ºè¯¥å¼ç大å°ã
max_connect_errors = #对äºåä¸ä¸»æºï¼å¦ææè¶ åºè¯¥åæ°å¼ä¸ªæ°çä¸æé误è¿æ¥ï¼å该主æºå°è¢«ç¦æ¢è¿æ¥ãå¦é对该主æºè¿è¡è§£ç¦ï¼æ§è¡ï¼FLUSH HOSTã
table_cache = #ç©çå åè¶å¤§,设置就è¶å¤§.é»è®¤ä¸º,è°å°-æä½³
external-locking = FALSE #使ç¨âskip-external-locking MySQLé项以é¿å å¤é¨éå®ã该é项é»è®¤å¼å¯
max_allowed_packet =8M #设置æ大å ,éå¶serveræ¥åçæ°æ®å 大å°ï¼é¿å è¶ é¿SQLçæ§è¡æé®é¢ é»è®¤å¼ä¸ºMï¼å½MySQL客æ·ç«¯æmysqldæå¡å¨æ¶å°å¤§äºmax_allowed_packetåèçä¿¡æ¯å æ¶ï¼å°ååºâä¿¡æ¯å è¿å¤§âé误ï¼å¹¶å ³éè¿æ¥ã对äºæäºå®¢æ·ç«¯ï¼å¦æéä¿¡ä¿¡æ¯å è¿å¤§ï¼å¨æ§è¡æ¥è¯¢æé´ï¼å¯è½ä¼éâ丢失ä¸MySQLæå¡å¨çè¿æ¥âé误ãé»è®¤å¼Mã
sort_buffer_size = 6M #ç¨äºè¡¨é´å ³èç¼åç大å°ï¼æ¥è¯¢æåºæ¶æè½ä½¿ç¨çç¼å²åºå¤§å°ã注æï¼è¯¥åæ°å¯¹åºçåé å åæ¯æ¯è¿æ¥ç¬å ï¼å¦ææ个è¿æ¥ï¼é£ä¹å®é åé çæ»å ±æåºç¼å²åºå¤§å°ä¸º à 6 ï¼ MBãæ以ï¼å¯¹äºå åå¨4GBå·¦å³çæå¡å¨æ¨è设置为6-8Mã
join_buffer_size = 6M #èåæ¥è¯¢æä½æè½ä½¿ç¨çç¼å²åºå¤§å°ï¼åsort_buffer_sizeä¸æ ·ï¼è¯¥åæ°å¯¹åºçåé å åä¹æ¯æ¯è¿æ¥ç¬äº«ã
thread_cache_size = #æå¡å¨çº¿ç¨ç¼åè¿ä¸ªå¼è¡¨ç¤ºå¯ä»¥éæ°å©ç¨ä¿åå¨ç¼åä¸çº¿ç¨çæ°é,å½æå¼è¿æ¥æ¶å¦æç¼åä¸è¿æ空é´,é£ä¹å®¢æ·ç«¯ç线ç¨å°è¢«æ¾å°ç¼åä¸,å¦æ线ç¨éæ°è¢«è¯·æ±ï¼ é£ä¹è¯·æ±å°ä»ç¼åä¸è¯»å,å¦æç¼åä¸æ¯ç©ºçæè æ¯æ°ç请æ±ï¼é£ä¹è¿ä¸ªçº¿ç¨å°è¢«éæ°å建,å¦ææå¾å¤æ°ç线ç¨ï¼å¢å è¿ä¸ªå¼å¯ä»¥æ¹åç³»ç»æ§è½.éè¿æ¯è¾ Connections å Threads_created ç¶æçåéï¼å¯ä»¥çå°è¿ä¸ªåéçä½ç¨
thread_concurrency = 8 #设置thread_concurrencyçå¼çæ£ç¡®ä¸å¦, 对mysqlçæ§è½å½±åå¾å¤§, å¨å¤ä¸ªcpu(æå¤æ ¸)çæ åµä¸ï¼é误设置äºthread_concurrencyçå¼, ä¼å¯¼è´mysqlä¸è½å åå©ç¨å¤cpu(æå¤æ ¸), åºç°åä¸æ¶å»åªè½ä¸ä¸ªcpu(ææ ¸)å¨å·¥ä½çæ åµãthread_concurrencyåºè®¾ä¸ºCPUæ ¸æ°ç2å. æ¯å¦æä¸ä¸ªåæ ¸çCPU, é£ä¹thread_concurrencyçåºè¯¥ä¸º4; 2个åæ ¸çcpu, thread_concurrencyçå¼åºä¸º8ï¼å±éç¹ä¼ååæ°
query_cache_size = 2M #æå®MySQLæ¥è¯¢ç¼å²åºç大å°ï¼å¨æ°æ®åºåå ¥éææ¯æ´æ°éä¹æ¯è¾å¤§çç³»ç»ï¼è¯¥åæ°ä¸éååé è¿å¤§ãèä¸å¨é«å¹¶åï¼åå ¥é大çç³»ç»ï¼å»ºç³»æ该åè½ç¦æã
query_cache_limit = 1M #é»è®¤æ¯4KBï¼è®¾ç½®å¼å¤§å¯¹å¤§æ°æ®æ¥è¯¢æ好å¤ï¼ä½å¦æä½ çæ¥è¯¢é½æ¯å°æ°æ®æ¥è¯¢ï¼å°±å®¹æé æå åç¢çå浪费
query_cache_min_res_unit = 2k #MySQLåæ°ä¸query_cache_min_res_unitæ¥è¯¢ç¼åä¸çåæ¯ä»¥è¿ä¸ªå¤§å°è¿è¡åé çï¼ä½¿ç¨ä¸é¢çå ¬å¼è®¡ç®æ¥è¯¢ç¼åçå¹³å大å°ï¼æ ¹æ®è®¡ç®ç»æ设置è¿ä¸ªåéï¼MySQLå°±ä¼æ´ææå°ä½¿ç¨æ¥è¯¢ç¼åï¼ç¼åæ´å¤çæ¥è¯¢ï¼åå°å åç浪费ã
default_table_type = InnoDB #é»è®¤è¡¨çå¼æ为InnoDB
thread_stack = K #éå®ç¨äºæ¯ä¸ªæ°æ®åºçº¿ç¨çæ 大å°ãé»è®¤è®¾ç½®è¶³ä»¥æ»¡è¶³å¤§å¤æ°åºç¨transaction_isolation = READ-COMMITTED #设å®é»è®¤çäºå¡é离级å«.å¯ç¨ç级å«å¦ä¸:
READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE,1.READ UNCOMMITTED-读æªæ交2.READ COMMITTE-读已æ交3.REPEATABLE READ -å¯éå¤è¯»4.SERIALIZABLE -串è¡
tmp_table_size = M #tmp_table_size çé»è®¤å¤§å°æ¯ Mãå¦æä¸å¼ 临æ¶è¡¨è¶ åºè¯¥å¤§å°ï¼MySQL产çä¸ä¸ª The table tbl_name is full å½¢å¼çé误ï¼å¦æä½ åå¾å¤é«çº§ GROUP BY æ¥è¯¢ï¼å¢å tmp_table_size å¼ã
max_heap_table_size = M #å å表ï¼å å表ä¸æ¯æäºå¡ï¼å å表使ç¨åå¸æ£åç´¢å¼ææ°æ®ä¿åå¨å åä¸ï¼å æ¤å ·ææå¿«çé度ï¼éåç¼åä¸å°åæ°æ®åºï¼ä½æ¯ä½¿ç¨ä¸åå°ä¸äºéå¶
long_query_time = 1 #è®°å½æ¶é´è¶ è¿1ç§çæ¥è¯¢è¯å¥
log_long_format #
log-error = /logs/error.log #å¼å¯mysqlé误æ¥å¿ï¼è¯¥é项æå®mysqldä¿åé误æ¥å¿æ件çä½ç½®
log-slow-queries = /logs/slow.log #æ ¢æ¥è¯¢æ¥å¿æ件路å¾
pid-file = /pids/mysql.pid
log-bin = /binlog/mysql-bin #binlogæ¥å¿ä½ç½®ä»¥åbinlogçå称
relay-log = /relaylog/relay-bin #relaylogæ¥å¿ä½ç½®ä»¥å称
binlog_cache_size = 1M #binlog_cache_size å°±æ¯æ»¡è¶³ä¸¤ç¹çï¼ä¸ä¸ªäºå¡ï¼å¨æ²¡ææ交ï¼uncommittedï¼çæ¶åï¼äº§ççæ¥å¿ï¼è®°å½å°Cacheä¸ï¼çå°äºå¡æ交ï¼committedï¼éè¦æ交çæ¶åï¼åææ¥å¿æä¹ åå°ç£çï¼é»è®¤æ¯Kã
max_binlog_cache_size = M #binlogç¼åæ大使ç¨çå å
max_binlog_size = 2M #ä¸ä¸ªbinlogæ¥å¿ç大å°
expire_logs_days = 7 #ä¿ç7天çbinlog
key_buffer_size = M #ç´¢å¼ç¼å大å°: å®å³å®äºæ°æ®åºç´¢å¼å¤ççé度ï¼å°¤å ¶æ¯ç´¢å¼è¯»çé度
read_buffer_size = M #MySqlè¯»å ¥ç¼å²åºå¤§å°ã对表è¿è¡é¡ºåºæ«æç请æ±å°åé ä¸ä¸ªè¯»å ¥ç¼å²åºï¼MySqlä¼ä¸ºå®åé ä¸æ®µå åç¼å²åºãread_buffer_sizeåéæ§å¶è¿ä¸ç¼å²åºç大å°ãå¦æ对表ç顺åºæ«æ请æ±é常é¢ç¹ï¼å¹¶ä¸ä½ 认为é¢ç¹æ«æè¿è¡å¾å¤ªæ ¢ï¼å¯ä»¥éè¿å¢å 该åéå¼ä»¥åå åç¼å²åºå¤§å°æé«å ¶æ§è½
read_rnd_buffer_size = 2M #MySQLçéæºè¯»ç¼å²åºå¤§å°ãå½æä»»æ顺åºè¯»åè¡æ¶(ä¾å¦ï¼æç §æåºé¡ºåº)ï¼å°åé ä¸ä¸ªéæºè¯»ç¼ååºãè¿è¡æåºæ¥è¯¢æ¶ï¼MySQLä¼é¦å æ«æä¸é该ç¼å²ï¼ä»¥é¿å ç£çæç´¢ï¼æé«æ¥è¯¢é度ï¼å¦æéè¦æåºå¤§éæ°æ®ï¼å¯éå½è°é«è¯¥å¼ãä½MySQLä¼ä¸ºæ¯ä¸ªå®¢æ·è¿æ¥åæ¾è¯¥ç¼å²ç©ºé´ï¼æ以åºå°½ééå½è®¾ç½®è¯¥å¼ï¼ä»¥é¿å å åå¼éè¿å¤§
bulk_insert_buffer_size = 1M #æ¹éæå ¥æ°æ®ç¼å大å°ï¼å¯ä»¥æææé«æå ¥æçï¼é»è®¤ä¸º8M
myisam_sort_buffer_size = 1M #MyISAM表åçååæ¶éæ°æåºæéçç¼å²
myisam_max_sort_file_size = G #MySQLé建索å¼æ¶æå 许çæ大临æ¶æ件çå¤§å° (å½ REPAIR, ALTER TABLE æè LOAD DATA INFILE). å¦ææ件大å°æ¯æ¤å¼æ´å¤§,ç´¢å¼ä¼éè¿é®å¼ç¼å²å建(æ´æ ¢)
myisam_repair_threads = 1 #å¦æä¸ä¸ªè¡¨æ¥æè¶ è¿ä¸ä¸ªç´¢å¼, MyISAM å¯ä»¥éè¿å¹¶è¡æåºä½¿ç¨è¶ è¿ä¸ä¸ªçº¿ç¨å»ä¿®å¤ä»ä»¬.è¿å¯¹äºæ¥æå¤ä¸ªCPU以å大éå åæ åµçç¨æ·,æ¯ä¸ä¸ªå¾å¥½çéæ©.
myisam_recover #èªå¨æ£æ¥åä¿®å¤æ²¡æéå½å ³éç MyISAM 表
lower_case_table_names = 1 #让mysqlä¸åºå大å°å
skip-name-resolve #ç¦ç¨DNS解æï¼è¿æ¥é度ä¼å¿«å¾å¤ãä¸è¿ï¼è¿æ ·çè¯å°±ä¸è½å¨MySQLçææ表ä¸ä½¿ç¨ä¸»æºåäºèåªè½ç¨ipæ ¼å¼ã
#slave-skip-errors = , #è¿æ¯é填项让slaveåºè·³è¿åªäºé误继ç»åæ¥
#replicate-ignore-db=mysql #éå¡«ï¼åæ¥æ¶ååªä¸ªæ°æ®åºä¸åæ¥è®¾ç½®
server-id = 1
innodb_additional_mem_pool_size = 4M #InnoDB åå¨çæ°æ®ç®å½ä¿¡æ¯åå ¶å®å é¨æ°æ®ç»æçå åæ± å¤§å°ãåºç¨ç¨åºéç表è¶å¤ï¼ä½ éè¦å¨è¿éåé è¶å¤çå åï¼é»è®¤æ¯2M
innodb_buffer_pool_size = M #è¿å¯¹Innodb表æ¥è¯´é常éè¦ãInnodbç¸æ¯MyISAM表对ç¼å²æ´ä¸ºææãMyISAMå¯ä»¥å¨é» 认ç key_buffer_size 设置ä¸è¿è¡çå¯ä»¥ï¼ç¶èInnodbå¨é»è®¤ç 设置ä¸å´è·èçä¼¼çãç±äºInnodbææ°æ®åç´¢å¼é½ç¼åèµ·æ¥ï¼æ éçç»æä½ç³»ç»å¤ªå¤çå åï¼å æ¤å¦æåªéè¦ç¨Innodbçè¯åå¯ä»¥è®¾ç½®å®é«è¾¾ -% çå¯ç¨å åãä¸äºåºç¨äº key_buffer çè§åæ â å¦æä½ çæ°æ®éä¸å¤§ï¼å¹¶ä¸ä¸ä¼æ´å¢ï¼é£ä¹æ éæ innodb_buffer_pool_size 设置ç太大äº
innodb_file_io_threads = 4 #æ件IOç线ç¨æ°ï¼ä¸è¬ä¸º 4
innodb_thread_concurrency = 8 #ä½ çæå¡å¨CPUæå 个就设置为å ,建议ç¨é»è®¤ä¸è¬ä¸º8
innodb_flush_log_at_trx_commit = 2 #é»è®¤ä¸º1ï¼å¦æå°æ¤åæ°è®¾ç½®ä¸º1ï¼å°å¨æ¯æ¬¡æ交äºå¡åå°æ¥å¿åå ¥ç£çã为æä¾æ§è½ï¼å¯ä»¥è®¾ç½®ä¸º0æ2ï¼ä½è¦æ¿æ å¨åçæ éæ¶ä¸¢å¤±æ°æ®çé£é©ã设置为0表示äºå¡æ¥å¿åå ¥æ¥å¿æ件ï¼èæ¥å¿æ件æ¯ç§å·æ°å°ç£çä¸æ¬¡ã设置为2表示äºå¡æ¥å¿å°å¨æ交æ¶åå ¥æ¥å¿ï¼ä½æ¥å¿æ件æ¯æ¬¡å·æ°å°ç£çä¸æ¬¡ã
innodb_log_buffer_size = 2M #æ¤åæ°ç¡®å®äºæ¥å¿æ件æç¨çå å大å°ï¼ä»¥M为åä½ãç¼å²åºæ´å¤§è½æé«æ§è½ï¼ä½æå¤çæ éå°ä¼ä¸¢å¤±æ°æ®.MySQLå¼å人å建议设置为1ï¼8Mä¹é´
innodb_log_file_size = 4M #æ¤åæ°ç¡®å®æ°æ®æ¥å¿æ件ç大å°ï¼ä»¥M为åä½ï¼æ´å¤§ç设置å¯ä»¥æé«æ§è½ï¼ä½ä¹ä¼å¢å æ¢å¤æ éæ°æ®åºæéçæ¶é´
innodb_log_files_in_group = 3 #为æé«æ§è½ï¼MySQLå¯ä»¥ä»¥å¾ªç¯æ¹å¼å°æ¥å¿æ件åå°å¤ä¸ªæ件ãæ¨è设置为3M
innodb_max_dirty_pages_pct = #Buffer_Poolä¸Dirty_Pageæå çæ°éï¼ç´æ¥å½±åInnoDBçå ³éæ¶é´ãåæ° innodb_max_dirty_pages_pctå¯ä»¥ç´æ¥æ§å¶äºDirty_Pageå¨Buffer_Poolä¸æå çæ¯çï¼èä¸å¹¸è¿çæ¯ innodb_max_dirty_pages_pctæ¯å¯ä»¥å¨ææ¹åçãæ以ï¼å¨å ³éInnoDBä¹åå è°å°ï¼å¼ºå¶æ°æ®åFlushä¸æ®µæ¶é´ï¼åè½å¤å¤§å¤§ç¼©çMySQLå ³éçæ¶é´ã
innodb_lock_wait_timeout = #InnoDB æå ¶å ç½®çæ»éæ£æµæºå¶ï¼è½å¯¼è´æªå®æçäºå¡åæ»ãä½æ¯ï¼å¦æç»åInnoDB使ç¨MyISAMçlock tables è¯å¥æ第ä¸æ¹äºå¡å¼æ,åInnoDBæ æ³è¯å«æ»éã为æ¶é¤è¿ç§å¯è½æ§ï¼å¯ä»¥å°innodb_lock_wait_timeout设置为ä¸ä¸ªæ´æ°å¼ï¼æ示 MySQLå¨å è®¸å ¶ä»äºå¡ä¿®æ¹é£äºæç»åäºå¡åæ»çæ°æ®ä¹åè¦çå¾ å¤é¿æ¶é´(ç§æ°)
innodb_file_per_table = 0 #ç¬äº«è¡¨ç©ºé´ï¼å ³éï¼
[mysqldump]
quick
max_allowed_packet = M
4. æ¶æä¼å
ï¼1ï¼. å端ç¨memcachedï¼redisçç¼ååæ æ°æ®åºåå
ï¼2ï¼. æ°æ®åºè¯»åå离ï¼è´è½½åè¡¡
ï¼3ï¼. æ°æ®åºååºå表
ï¼4ï¼. åå¨å¯éååå¸å¼
5. åæä¼å
主è¦æ¯å¤è§å¯ï¼åæå°±æ¯ç»´æ¤å·¥ä½äºï¼è§å¯æå¡å¨è´è½½æ¯éè¦æ·»å 硬件äºï¼è¿æ¯æè¯å¥æé®é¢åï¼è¿æ¯åæ°è¦ä¿®æ¹äºã
6. æ¥è¯¢ä¼åï¼ææå«äººçï¼
. 使ç¨æ ¢æ¥è¯¢æ¥å¿å»åç°æ ¢æ¥è¯¢ã
. 使ç¨æ§è¡è®¡åå»å¤ææ¥è¯¢æ¯å¦æ£å¸¸è¿è¡ã
. æ»æ¯å»æµè¯ä½ çæ¥è¯¢ççæ¯å¦ä»ä»¬è¿è¡å¨æä½³ç¶æä¸ âä¹ èä¹ ä¹æ§è½æ»ä¼ååã
. é¿å å¨æ´ä¸ªè¡¨ä¸ä½¿ç¨count(*),å®å¯è½éä½æ´å¼ 表ã
. 使æ¥è¯¢ä¿æä¸è´ä»¥ä¾¿åç»ç¸ä¼¼çæ¥è¯¢å¯ä»¥ä½¿ç¨æ¥è¯¢ç¼åã
. å¨éå½çæ å½¢ä¸ä½¿ç¨GROUP BYèä¸æ¯DISTINCTã
. å¨WHERE, GROUP BYåORDER BYåå¥ä¸ä½¿ç¨æç´¢å¼çåã
. ä¿æç´¢å¼ç®å,ä¸å¨å¤ä¸ªç´¢å¼ä¸å å«åä¸ä¸ªåã
. ææ¶åMySQLä¼ä½¿ç¨é误çç´¢å¼,对äºè¿ç§æ åµä½¿ç¨USE INDEXã
. æ£æ¥ä½¿ç¨SQL_MODE=STRICTçé®é¢ã
. 对äºè®°å½æ°å°äº5çç´¢å¼å段ï¼å¨UNIONçæ¶å使ç¨LIMITä¸æ¯æ¯ç¨OR.
. ä¸ºäº é¿å å¨æ´æ°åSELECTï¼ä½¿ç¨INSERT ON DUPLICATE KEYæè INSERT IGNORE ,ä¸è¦ç¨UPDATEå»å®ç°ã
. ä¸è¦ä½¿ç¨ MAX,使ç¨ç´¢å¼å段åORDER BYåå¥ã
. é¿å 使ç¨ORDER BY RAND().
ãLIMIT Mï¼Nå®é ä¸å¯ä»¥åç¼æ¥è¯¢å¨æäºæ åµä¸ï¼æèå¶å°ä½¿ç¨ã
ãå¨WHEREåå¥ä¸ä½¿ç¨UNION代æ¿åæ¥è¯¢ã
ã对äºUPDATESï¼æ´æ°ï¼ï¼ä½¿ç¨ SHARE MODEï¼å ±äº«æ¨¡å¼ï¼ï¼ä»¥é²æ¢ç¬å éã
ãå¨éæ°å¯å¨çMySQLï¼è®°å¾æ¥æ¸©æä½ çæ°æ®åºï¼ä»¥ç¡®ä¿æ¨çæ°æ®å¨å ååæ¥è¯¢é度快ã
ã使ç¨DROP TABLEï¼CREATE TABLE DELETE FROMä»è¡¨ä¸å é¤æææ°æ®ã
ãæå°åçæ°æ®å¨æ¥è¯¢ä½ éè¦çæ°æ®ï¼ä½¿ç¨*æ¶è大éçæ¶é´ã
ãèèæä¹ è¿æ¥ï¼èä¸æ¯å¤ä¸ªè¿æ¥ï¼ä»¥åå°å¼éã
ãåºåæ¥è¯¢ï¼å æ¬ä½¿ç¨æå¡å¨ä¸çè´è½½ï¼ææ¶ä¸ä¸ªç®åçæ¥è¯¢å¯ä»¥å½±åå ¶ä»æ¥è¯¢ã
ãå½è´è½½å¢å æ¨çæå¡å¨ä¸ï¼ä½¿ç¨SHOW PROCESSLISTæ¥çæ ¢çåæé®é¢çæ¥è¯¢ã
ãå¨å¼åç¯å¢ä¸äº§ççéåæ°æ®ä¸ æµè¯çææå¯ççæ¥è¯¢ã
在英特尔 CPU 上微调 Stable Diffusion 模型
扩散模型,一种能够根据文本提示生成逼真图像的能力,显著推动了生成式人工智能的普及。这些模型广泛应用于数据合成和内容创建等领域,金币棋牌游戏源码Hugging Face Hub 上拥有超过5千个预训练的文生图模型。结合Diffusers库,构建图像生成工作流或实验不同的图像生成流程变得极为简便。
微调扩散模型以满足特定业务需求的图像生成,通常依赖于GPU。然而,这一情况正在发生变化。英特尔推出了代号为Sapphire Rapids的第四代至强CPU,其中包含英特尔先进矩阵扩展(AMX),专门用于加速深度学习工作负载。在之前的博文中,我们已经展示了AMX的优势,包括微调NLP transformer模型、对NLP transformer模型进行推理以及对Stable Diffusion模型进行推理。
本文将展示如何在英特尔第四代至强CPU集群上微调Stable Diffusion模型。我们采用文本逆向(Textual Inversion)技术进行微调,仅需少量训练样本即可有效调整模型。使用5个样本即可实现。
配置集群时,我们利用英特尔开发者云提供的服务器。这些服务器配置了英特尔第四代至强CPU,每颗CPU包含个物理核和个线程。通过nodefile文件,我们管理了服务器IP地址,其中第一行指为主服务器。
分布式训练要求主节点与其他节点之间实现无密码SSH通信。区块猫源码演示设置无密码SSH,参考相关文章步骤操作。
搭建运行环境并安装所需软件,包括英特尔优化库如oneCCL和Intel Extension for PyTorch(IPEX),以利用Sapphire Rapids的硬件加速功能。此外,我们安装了高性能内存分配库libtcmalloc及其软件依赖项gperftools。
在每个节点上,我们克隆diffusers代码库并进行源码安装。对diffusers/examples/textual_inversion中的微调脚本进行优化,利用IPEX对U-Net和变分自编码器(VAE)模型进行推理优化。
下载训练图像,确保在所有节点上的目录路径一致。微调任务启动后,加速器会自动在节点间建立分布式的训练。
配置微调环境时,使用accelerate库简化分布式训练。在每个节点上运行acclerate config并回答问题。设置环境变量,确保所有节点间的通信。
启动微调,使用mpirun在nodefile列出的节点间建立分布式通信。运行命令训练步,耗时约5分钟。训练过程中的集群状态显示在截图中。
分布式训练中可能出现的水循环指标源码错误通常包括单节点配置错误,如依赖项缺失或图像位置不同。登录各节点并本地训练可快速定位问题。如果所有节点的训练均成功启动,检查nodefile、环境和mpirun命令。
微调模型后,直接使用diffusers的pipeline加载模型进行图像生成。进一步使用Optimum Intel和OpenVINO对模型进行推理优化。优化后,仅用单颗CPU即可在不到5秒内生成图像。
加载优化后的模型,生成5张不同图像并保存。生成的图像显示模型仅用5张图像就能识别dicoo戴眼镜。对模型进行更多微调,如步,可获得更佳效果。
借助Hugging Face与英特尔的合作,现在能够利用至强CPU服务器生成符合业务需求的高质量图像。CPU不仅比GPU等专用硬件更便宜且易得,还能轻松执行其他任务如Web服务器、数据库等,成为IT基础设施的多功能灵活选择。
入门资源包括:
如有任何疑问或反馈,请访问Hugging Face论坛留言。
Spring Boot引起的“堆外内存泄漏”排查及经验总结
为了更好地实现对项目的管理,我们将组内一个项目迁移到MDP框架(基于Spring Boot),桂林林源码头随后我们就发现系统会频繁报出Swap区域使用量过高的异常。笔者被叫去帮忙查看原因,发现配置了4G堆内内存,但是实际使用的物理内存竟然高达7G,确实不正常。JVM参数配置是“-XX:MetaspaceSize=M -XX:MaxMetaspaceSize=M -XX:+AlwaysPreTouch -XX:ReservedCodeCacheSize=m -XX:InitialCodeCacheSize=m, -Xssk -Xmx4g -Xms4g,-XX:+UseG1GC -XX:G1HeapRegionSize=4M”,实际使用的物理内存如下图所示:
使用Java层面的工具定位内存区域(堆内内存、Code区域或者使用unsafe.allocateMemory和DirectByteBuffer申请的堆外内存)。
笔者在项目中添加-XX:NativeMemoryTracking=detailJVM参数重启项目,使用命令jcmd pid VM.native_memory detail查看到的内存分布如下:
发现命令显示的committed的内存小于物理内存,因为jcmd命令显示的内存包含堆内内存、Code区域、通过unsafe.allocateMemory和DirectByteBuffer申请的内存,但是不包含其他Native Code(C代码)申请的堆外内存。所以猜测是使用Native Code申请内存所导致的问题。
为了防止误判,笔者使用了pmap查看内存分布,发现大量的M的地址;而这些地址空间不在jcmd命令所给出的地址空间里面,基本上就断定就是这些M的内存所导致。
使用系统层面的工具定位堆外内存。
因为已经基本上确定是Native Code所引起,而Java层面的工具不便于排查此类问题,只能使用系统层面的工具去定位问题。
首先,使用了gperftools去定位问题。
从上图可以看出:使用malloc申请的的内存最高到3G之后就释放了,之后始终维持在M-M。笔者第一反应是:难道Native Code中没有使用malloc申请,直接使用mmap/brk申请的?(gperftools原理就使用动态链接的方式替换了操作系统默认的内存分配器(glibc)。)
然后,使用strace去追踪系统调用。
因为使用gperftools没有追踪到这些内存,于是直接使用命令“strace -f -e"brk,mmap,munmap" -p pid”追踪向OS申请内存请求,但是并没有发现有可疑内存申请。
接着,使用GDB去dump可疑内存。
因为使用strace没有追踪到可疑内存申请;于是想着看看内存中的情况。就是直接使用命令gdp -pid pid进入GDB之后,然后使用命令dump memory mem.bin startAddress endAddressdump内存,其中startAddress和endAddress可以从/proc/pid/smaps中查找。然后使用strings mem.bin查看dump的内容,如下:
从内容上来看,像是解压后的JAR包信息。读取JAR包信息应该是在项目启动的时候,那么在项目启动之后使用strace作用就不是很大了。所以应该在项目启动的时候使用strace,而不是启动完成之后。
再次,项目启动时使用strace去追踪系统调用。
项目启动使用strace追踪系统调用,发现确实申请了很多M的内存空间,截图如下:
使用该mmap申请的地址空间在pmap对应如下:
最后,使用jstack去查看对应的线程。
因为strace命令中已经显示申请内存的线程ID。直接使用命令jstack pid去查看线程栈,找到对应的线程栈(注意进制和进制转换)如下:
这里基本上就可以看出问题来了:MCC(美团统一配置中心)使用了Reflections进行扫包,底层使用了Spring Boot去加载JAR。因为解压JAR使用Inflater类,需要用到堆外内存,然后使用Btrace去追踪这个类,栈如下:
然后查看使用MCC的地方,发现没有配置扫包路径,默认是扫描所有的包。于是修改代码,配置扫包路径,发布上线后内存问题解决。
为什么堆外内存没有释放掉呢?
虽然问题已经解决了,但是有几个疑问。带着疑问,直接看了一下 Spring Boot Loader那一块的源码。发现Spring Boot对Java JDK的InflaterInputStream进行了包装并且使用了Inflater,而Inflater本身用于解压JAR包的需要用到堆外内存。而包装之后的类ZipInflaterInputStream没有释放Inflater持有的堆外内存。于是以为找到了原因,立马向Spring Boot社区反馈了这个bug。但是反馈之后,就发现Inflater这个对象本身实现了finalize方法,在这个方法中有调用释放堆外内存的逻辑。也就是说Spring Boot依赖于GC释放堆外内存。
使用jmap查看堆内对象时,发现已经基本上没有Inflater这个对象了。于是就怀疑GC的时候,没有调用finalize。带着这样的怀疑,把Inflater进行包装在Spring Boot Loader里面替换成自己包装的Inflater,在finalize进行打点监控,结果finalize方法确实被调用了。于是又去看了Inflater对应的C代码,发现初始化的使用了malloc申请内存,end的时候也调用了free去释放内存。
此时,怀疑free的时候没有真正释放内存,便把Spring Boot包装的InflaterInputStream替换成Java JDK自带的,发现替换之后,内存问题也得以解决了。
再次看gperftools的内存分布情况,发现使用Spring Boot时,内存使用一直在增加,突然某个点内存使用下降了好多(使用量直接由3G降为M左右)。这个点应该就是GC引起的,内存应该释放了,但是在操作系统层面并没有看到内存变化,那是不是没有释放到操作系统,被内存分配器持有了呢?
继续探究,发现系统默认的内存分配器(glibc 2.版本)和使用gperftools内存地址分布差别很明显,2.5G地址使用smaps发现它是属于Native Stack。内存地址分布如下:
到此,基本上可以确定是内存分配器在捣鬼;搜索了一下glibc M,发现glibc从2.开始对每个线程引入内存池(位机器大小就是M内存),原文如下:
按照文中所说去修改MALLOC_ARENA_MAX环境变量,发现没什么效果。查看tcmalloc(gperftools使用的内存分配器)也使用了内存池方式。
为了验证是内存池搞的鬼,就简单写个不带内存池的内存分配器。使用命令gcc zjbmalloc.c -fPIC -shared -o zjbmalloc.so生成动态库,然后使用export LD_PRELOAD=zjbmalloc.so替换掉glibc的内存分配器。其中代码Demo如下:
通过在自定义分配器当中埋点可以发现实际申请的堆外内存始终在M-M之间,gperftools监控显示内存使用量也是在M-M左右。但是从操作系统角度来看进程占用的内存差别很大(这里只是监控堆外内存)。
使用不同分配器进行不同程度的扫包,占用的内存如下:
为什么自定义的malloc申请M,最终占用的物理内存在1.7G呢?因为自定义内存分配器采用的是mmap分配内存,mmap分配内存按需向上取整到整数个页,所以存在着巨大的空间浪费。通过监控发现最终申请的页面数目在k个左右,那实际上向系统申请的内存等于k * 4k(pagesize) = 2G。
为什么这个数据大于1.7G呢?因为操作系统采取的是延迟分配的方式,通过mmap向系统申请内存的时候,系统仅仅返回内存地址并没有分配真实的物理内存。只有在真正使用的时候,系统产生一个缺页中断,然后再分配实际的物理Page。
整个内存分配的流程如上图所示。MCC扫包的默认配置是扫描所有的JAR包。在扫描包的时候,Spring Boot不会主动去释放堆外内存,导致在扫描阶段,堆外内存占用量一直持续飙升。当发生GC的时候,Spring Boot依赖于finalize机制去释放了堆外内存;但是glibc为了性能考虑,并没有真正把内存归返到操作系统,而是留下来放入内存池了,导致应用层以为发生了“内存泄漏”。所以修改MCC的配置路径为特定的JAR包,问题解决。在发表这篇文章时,发现Spring Boot的最新版本(2.0.5.RELEASE)已经做了修改,在ZipInflaterInputStream主动释放了堆外内存不再依赖GC;所以Spring Boot升级到最新版本,这个问题也可以得到解决。