[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"site":3,"post-swap-dui-shang-xian-he-gou-jian-nei":59,"related-swap-dui-shang-xian-he-gou-jian-nei":85},{"name":4,"url":5,"description":6,"bio":7,"avatar":8,"skills":9,"tools":16,"social":34,"hero":47,"heatmap":52,"icp":55,"police":56,"policeIcon":57,"shortName":58},"时过境迁技术笔记","https:\u002F\u002Fhsgjq.top","一个记录前端与 Node 实践的个人博客，内容围绕 Vue、Nuxt、NestJS 与工程化展开，附源码级的原理笔记。","一名热爱技术的全栈开发者，专注 TypeScript 与 Web 工程化，习惯把踩过的坑和思考记录在这里。","\u002Fuploads\u002Fc485c101-179e-48db-96d1-238693784c38.jpg",[10,11,12,13,14,15],"TypeScript","Vue 3","Nuxt","NestJS","Node.js","工程化",[17,23,28],{"items":18,"title":22},[19,20,21],"Cursor","Git","Chrome DevTools","开发工具",{"items":24,"title":27},[25,26],"Vite","npm","构建工具",{"items":29,"title":33},[30,31,32],"Docker","CI\u002FCD(GitHub Actions)","Vercel","部署运维",[35,39,43],{"href":36,"icon":37,"label":38},"https:\u002F\u002Fgithub.com\u002Fhsgjq","github","GitHub",{"href":40,"icon":41,"label":42},"2971861643@qq.com","mail","邮箱",{"href":44,"icon":45,"label":46},"\u002Frss.xml","rss","RSS",{"lines":48,"subtitle":51},[49,50],"人生若只如初见，","何事秋风悲画扇。","《木兰花·拟古决绝词柬友》",{"enabled":53,"platform":37,"username":54},true,"hsgjq","桂ICP备2024046985号","桂公网安备45011002000103号","\u002Fuploads\u002F72c67ef3-bc86-4b64-b0df-0aba71065050.png","时过境迁",{"slug":60,"title":61,"excerpt":62,"date":63,"updatedAt":64,"tags":65,"content":66,"series":67,"seriesIndex":68,"seriesNav":69,"prev":79,"next":82},"swap-dui-shang-xian-he-gou-jian-nei","swap、堆上限和构建内存墙","swap 让构建不被杀但变慢，抬堆上限让 Node 敢用更多内存，两件事要一起做。试过的几个数字和哪个最后成了，都写在里面。","2026-08-20","2026-10-19",[30],"接着上一篇，把三件事的关系说清楚，因为我一开始把两个概念混了。\n\nV8 的堆上限是\"这个 JS 进程最多能申请多少内存\"。它跟物理内存无关，是一个软限制，默认按机器内存推算。Node 在 1.9G 的机器上给的大约是 2G 不到，但构建过程中实际峰值需要更多，于是先撞到这个软限制，报 heap out of memory。抬它是告诉 V8：\"允许你继续要。\"\n\nswap 是\"要了之后真给得出\"。没有 swap，抬高的上限就是空头支票，进程会一路申请到物理内存加缓存全满，然后被内核 OOM killer 挑中杀掉——表现是没有任何 JS 报错，进程直接消失。\n\n所以两个必须一起调。只抬上限，撞墙的方式从 V8 报错变成被内核杀；只加 swap，V8 还是会在自己的上限前退出。\n\n调完还要看它到底用了多少。构建时另开一个终端：\n\n```bash\nwatch -n 2 free -h\n```\n\nSwap used 那一列如果一路涨到 1.5G，说明构建确实吃到了 swap，慢是必然的。这时该考虑的不是继续加数字，而是换地方构建。\n\n几条经验性的判断：\n\n构建慢和构建失败是两回事，别用加内存解决慢。\n容器里的内存限制（mem_limit）如果比堆上限低，先撞的是容器那层，报错也很含糊。\n最省心的解法是别让生产机参与构建。我这台 1.9G 的机器后来只负责 pull 和跑，构建交给 CI，一次配置换来以后所有发版都不再关心内存。","工程化与部署",12,[70,74,75],{"slug":71,"title":72,"seriesIndex":73},"tu-pian-dao-di-cun-na-cong-dui","图片到底存哪：从对象存储的念头回到自建目录",11,{"slug":60,"title":61,"seriesIndex":68},{"slug":76,"title":77,"seriesIndex":78},"cong-da-bao-shang-chuan-dao-push-ji","从打包上传到 push 即上线：把 CD 接通",13,{"slug":80,"title":81},"1-9g-nei-cun-de-fu-wu-qi","1.9G 内存的服务器上，nuxt build 在第 36 秒被杀",{"slug":83,"title":84},"wo-ba-compose-de-override-xie-cuo-zhan","我把 compose 的 override 写错，站点停了二十分钟",[86,90,94,98,108],{"slug":76,"title":77,"excerpt":87,"date":88,"tags":89},"私有仓库的镜像包默认也是私有的，健康检查的探测地址在宿主机有 nginx 时会打错地方。两处都是配好之后才验出来的。","2026-10-02",[30,15],{"slug":83,"title":84,"excerpt":91,"date":92,"tags":93},"ports 是追加不是替换，合并之后 80 端口撞了；而 up 失败前旧容器已经被换掉。配置检查命令的输出格式也骗了我一次。","2026-09-03",[30],{"slug":80,"title":81,"excerpt":95,"date":96,"tags":97},"V8 堆耗尽直接 SIGABRT，日志里只有一句低内存提示。先分清是被系统杀的还是自己崩的，再决定加内存还是加 swap。","2026-08-08",[30],{"slug":99,"title":100,"excerpt":101,"date":102,"tags":103},"gang-deng-lu-jiu-guo-qi-yi-ci","一个 401，查出四个前端机制：缓存回放、隐藏页的 rAF、百分比圆角、缓动过冲","响应头里的 token 被 304 原样回放，把刚签发的新 token 顶掉，表现成刚登录就过期。顺带记三个前端细节：隐藏标签页里 rAF 不执行、扁盒子的 50% 圆角是胶囊、缓动曲线的过冲只有 0.0008。","2026-10-13",[104,105,106,107],"CSS","JavaScript","Vue","浏览器",{"slug":109,"title":110,"excerpt":111,"date":88,"tags":112},"dian-xiang-mu-ye-mian-jiu-si-yi","点「项目」页面就死：一次客户端无限重定向","为了保留旧地址大小写加的一条跳转规则，被注册成了客户端路由；路由匹配不区分大小写，于是它自己跳自己。",[12,107]]