GitHub 今日推荐|REDox:64 位 token 表示结构化数据,内存占用降 70% 支持多格式互转
掘金
CAPCOM 下一代游戏引擎核心数据引擎,用 64 位固定尺寸 token 表示结构化数据作为中间表示,延迟解码未修改值减少内存分配 70%,通过格式无关 DataReader/DataWriter
Score: 57.31Confidence: 54%
View offerLoading the catalog…
THE AI OPPORTUNITY INDEX
Find your next AI tool. Explore free access, trials, and credits — all in one place.
掘金
CAPCOM 下一代游戏引擎核心数据引擎,用 64 位固定尺寸 token 表示结构化数据作为中间表示,延迟解码未修改值减少内存分配 70%,通过格式无关 DataReader/DataWriter
Score: 57.31Confidence: 54%
View offerReadhub
距离 Anthropic 预计 IPO 仅剩不到四十天,公司计划 10 月 14 日举办 Pre-IPO 投资者日,最快 11 月 9 日启动路演,争取感恩节前敲钟,目标估值 2 万亿美金,有望成为人类历史上规模最大的 IPO。在此关键节点,被称为 Anthropic「第一夫人」的 CEO Dario 的妻子 Cami Clark 悄然退场。Cami 从未在 Anthropic 领过工资、没有工牌和正式职位,却深度参与公司战略讨论、筛选投资邀约、介入 CEO 公共形象管理和安保决策,是公司非正式体系下影响力极大的人物,相关个人信息长期被设法删除。Cami 出身普通,早年创业几经波折,曾接触爱泼斯坦寻求投资未果,凭借硅谷人脉积累,她为 Anthropic 牵线拿到了埃里克・施密特的 A 轮投资,是撬动公司早期发展的关键人物。此次 Cami 退场,正值 Anthropic 推进从创始人私人权力圈转向制度化的治理转型,公司独特的长期利益信托架构中没有非正式影子顾问的位置,这类非正式权力是 IPO 前治理审计的重大风险项,Cami 的出局是 Anthropic 走向规范化治理的关键节点。
Score: 57.28Confidence: 54%
View offerReadhub
全球各地的苹果 Apple Store 本周收到一批印有 10 月 8 日前禁止开启贴纸的保密箱,箱内物品为苹果智能家居产品的宣传物料,供员工在产品发布前更新门店标签、宣传海报和产品陈列布局。这批物料虽有推测认为可能关联苹果首款折叠屏手机 iPhone Duo,但更可能与 HomeHub 智能家居中枢有关,苹果计划在 10 月 13 日推出智能家庭中枢 HomeHub、新款 Apple TV 4K 以及 HomePod mini 2。
Score: 57.28Confidence: 54%
View offerReadhub
2026 年沃尔夫物理学奖揭晓,华人物理学家叶军与德国物理学家伊曼努尔・布洛赫共同获奖,这是该奖项设立 48 年来第二次颁给华人科学家。沃尔夫基金会评价二人在超冷原子系统调控领域取得了变革性且具广泛适用性的突破,将实验物理带入了过去几乎无法操控的领域。叶军研发的锶光晶格钟精度不断突破,2024 年创下的精度达到从宇宙大爆炸至今误差不到半秒的水平,还首次将钍-229 原子核的跃迁频率与原子钟直接连接,测量精度较此前提升约 100 万倍。布洛赫利用光晶格开创量子模拟领域,实现了物态的激光调控,其成果被视为量子模拟实验的开端,后续研发的量子气体显微镜成为相关领域研究利器,近期还在冷原子平台实现了高保真度量子门。沃尔夫物理学奖素有「诺奖风向标」之称,过往获奖者中约 36% 后续获得诺贝尔物理学奖,本次奖项公布距当年诺贝尔物理学奖揭晓仅数日,叶军此前已多次入围诺奖预测,光晶格钟领域被认为迟早会获得诺奖。
Score: 57.28Confidence: 54%
View offerReadhub
苹果公司首款智能家居中枢将采用 AI 面部识别,可判断当前家庭成员并显示对应内容。
Score: 57.28Confidence: 54%
View offerReadhub
Anthropic 计划到 2027 年将前沿工程师团队扩大至 1 万人。
Score: 57.28Confidence: 54%
View offerReadhub
美乌联合重建投资基金敲定成立以来首个关键矿产项目,新增 4 个能源等领域项目,累计项目达 6 个,总规模约 7000 万美元。首个矿产项目将向乌克兰 BGV 集团旗下联合投资平台投入约 3000 万美元,初期投资乌克兰早期矿业项目,重点开发美国关键矿产清单所列的稀土、铀、铍和锆等资源。基金还将投资乌克兰电力和供热系统,增强遭袭基础设施的供电和供热能力。该基金源于美乌去年 4 月签署的矿产协议,重点投资矿产、国防、能源和基础设施等战略领域。
Score: 57.25Confidence: 54%
View offer人人都是产品经理
火起来的不是视频生成模型,而是让 Claude Code、Codex 这类工具写 HTML、Canvas 或 Remotion 动画,再逐帧导出 MP4,字幕、镜头和转场都在代码里调。文章整理了外网 10 支成品,又挑了五个能上手的开源项目。 好好好,Jev 模型和 GPT-6 做 3D 的爆火浪潮还没过去。 大家就研究出来 用Claude Opus 5.5 做视频。 这里提到的做视频不是 Seedance 这类模型的视频生成。 而是让 Claude Code、Codex 等 Agent 工具 编写 HTML、Canvas、WebGL 或 Remotion 动画,然后逐帧导出 MP4。 字幕、镜头路径和转场都可以在代码里调整。 所以现在你应该能刷到很多用 Claude Opus 5.5 做的 产品发布片、动态图解,甚至五分钟的历史电影。 模型的代码能力到了一个门槛,真的很多场景的可用性就很高了。 01 先看 10 支成品 1 小女孩问 Claude:你喜欢什么? 让 Opus 5.5 用 JavaScript 逐帧画出一支约 28 秒的手绘短片。 镇上的人不断向 Claude 提需求,一个女孩却问它喜欢什么。 画面随着回答切到大海、动物和星星,最后又回到女孩的窗前。 https://x.com/kevin_t_ngo/status/2102437977435893771 2. 一个按钮,连续变成整支视频 给 Opus 5.5 的任务是用一个 HTML 文件拍完这支界面短片。 按钮先伸展成播放器,画面继续变为图表和命令面板,光标每次点击都推动下一次转场。 这个帖子的提示词还写明了逐帧计算和导出方法。 https://x.com/twoclipping/status/2103273003555402193 单个 HTML 页面用时间参数计算每一帧的元素位置和形状,因此任何时刻的画面都能准确重现。Playwright 截取浏览器画面,再由 FFmpeg 合成为视频。 3. 镜头一路钻进 Blackwell 芯片 Lucian 做了一段约 49 秒的镜头,带观众从数据中心钻进服务器,再穿过芯片,直到原子尺度。 整个三维场景装在一个 HTML 文件里,由 Opus 5.5 编写的 Three.js 代码在浏览器中实时绘制。 https://x.com/lucian__03/status/2103494418477260830 原理就是 Three.js 实时渲染机房、服务器和芯片等三维场景,连续推进的镜头把不同尺度串成一次穿梭。 4. 一张鸡尾酒图,变成 30 秒的调制动画 给模型一张参考图,让它用 HTML 把静态画面扩展成完整的调制过程。 配料逐步出现,画面同时标出步骤和用量。 提示词就在原帖。 https://x.com/Ror_Fly/status/2102853258582880547 核心原理就是参考图提供杯子、配料和文字的视觉样式,HTML 动画再按时间顺序展开调制步骤。 5. 两分钟沙画,讲美国 250 年历史 这个是让 Opus 5.5 用两分钟沙画讲 250 年美国历史,再配上音乐和音效。 用代码把不同历史节点组织成一段连续的沙画叙事,并生成配乐与音效。 https://x.com/Michaelzsguo/status/2102592355165782312 6. 一句需求,做出推理产品介绍片 让 Opus 5.5 给一家提供推理服务的创业公司做利落的介绍视频,得到约 26 秒的成片。 JavaScript 控制文字、图形和转场随时间变化, 再用 Playwright 和 FFmpeg 导出。 https://x.com/deedydas/status/2102787937482252537 7. 一支产品歌短片 这个是用 Opus 5.5 和 JavaScript 制作了约 28 秒的 Replit Animation 宣传片。 橙色图形和产品画面随着音乐切换。 Opus 5.5 编写 JavaScript 来安排图形运动和剪辑节奏,Replit Animation 提供工程搭建与导出能力。 https://x.com/samuel_spitz/status/2103293794594816100 8. 五分钟的奥斯特里茨战役电影 五分钟的历史影片,WebGL 程序按照叙事时间线渲染战场和镜头运动,再把生成的声音、离线旁白与画面合成。 镜头从地图推进到士兵行动,最后形成一支有叙事节奏的影片。 https://github.com/WinterArc21/Battle-of-Austerlitz-Film 9. 用剪纸动画解释相对论 日本创作者让 Opus 5.5 用 JavaScript 在 Canvas 上逐帧画出约 46 秒的相对论科普片,音乐和音效也由代码生成。 剪纸般的纸片、星球和人物解释了双生子佯谬。 https://x.com/masahirochaen/status/2102722719502704941 10. 40 秒讲清浏览器怎样工作 Addy Osmani 让 Opus 5.5 用 JavaScript 逐帧 画出一支《浏览器如何工作》的解释动画。 页面、网络请求和渲染过程被画成会动的图解。 https://x.com/addyosmani/status/2103009037164110327 02 相关开源项目 下面是我找到的几个 GitHub 上用 Opus 5.5 做视频的一些开源项目,有的是搞了一些风格,有的是有一些提示词开源的,你可以看一看了解一下。 1 30 种影片画面风格 Lemo-Opuscar 这个开源项目 收集了 39 种用 Opus 5.5 做成的影片风格 ,每一种都配有样片和说明。 先在样片库里挑一种喜欢的视觉效果,再把自己的主题交给它的 Skill。 开源地址:https://github.com/lemomo-ai/lemo-opuscar 2 Awesome-Opus5-5-Videos 还有一个很火的开源项目。 一共301 个 Opus 5.5 视频,开发者花了整整 $3000。 用 Claude Opus 5.5 把全网最难、最火的特效重新做了一遍。 所有测试视频、全套 Prompt 和工作流,全部整理开源。 地址:https://github.com/yihui-dev/awesome-opus5-5-videos 3 提示词大合集 这个开源项目是 Opus 5.5 视频 提示词合集。 它把不同作者的成片和提示词放在一起,方便顺着喜欢的视频找写法。 开源地址:https://github.com/joeseesun/opus-video-prompts 4 想把镜头和转场做得更顺 OneTake 收集了一镜到底产品视频的动作和制作拆解,还提供可复用的 Skill。 如果你想用 Claude Code 生成下面这种视频的话,可以研究研究这个开源项目。 地址:https://github.com/feitangyuan/onetake 5两个老牌的项目 HyperFrames 可以把 HTML 动画渲染成视频。 Remotion 官方 Agent Skills则教 Agent 用 React 代码制作、预览和导出视频。 这两个 skill 是 GitHub 上比较火的让 AI 通过 Coding 方式做视频的高赞项目。 地址:https://github.com/heygen-com/hyperframes 地址:https://github.com/remotion-dev/skills 另外还有其它 AI Coding 的方式生成视频的 Case 或项目。 作者:逛逛GitHub 公众号:逛逛GitHub 本文由 @逛逛GitHub 原创发布于人人都是产品经理。未经作者许可,禁止转载 题图来自 Unsplash,基于CC0协议
iThome 新聞
美國社群新聞與討論平臺Reddit周三(9/30)宣布進一步限制外部程式大量取得平臺內容,將於11月13日停止支援簡易資訊聚合(Really Simple Syndication,RSS),並逐步關閉Public API存取,2027年3月全面停止Public API公開存取,以減少大規模資料爬取及自動化濫用。
Score: 56.42Confidence: 54%
View offer爱范儿
星舰是现在,太空计算是未来 #欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。
Score: 55.57Confidence: 54%
View offervelog
항목 이 구현의 선택 빈 블록 관리 묵시적 빈 리스트 블록 형식 헤더 + 페이로드 + 푸터 (경계 태그) 배치 정책 first fit 연결 free 시점에 즉시 연결 정렬 8바이트 (더블워드) 워드 크기 4바이트 0. 할당기가 풀어야 할 네 가지 질문 (9.9.5) 가장 단순한 할당기는 힙을 큰 바이트 배열로 보고 포인터 p 만 유지함. malloc 은 p 를 size만큼 올리고, free 는 아무것도 안 함. 처리량은 최고지만 블록을 재사용하지 않아서 이용도는 최악임. 그래서 실용적인 할당기는 네 가지를 정해야 함. 질문 이 구현의 답 코드 빈 블록을 어떻게 추적? 묵시적 리스트 헤더 크기를 따라 순회 어느 빈 블록에 넣을까? (배치) first fit find_fit 남는 부분은? (분할) 나머지가 16B 이상이면 분할 place 해제된 블록은? (연결) 즉시 연결 mm_free → coalesce 할당기의 제약과 목표 (9.9.3) 제약 임의의 malloc / free 순서를 처리해야 함 요청을 모았다가 재배열하지 않고 즉시 응답 해야 함 할당기의 자료구조도 힙 안에만 저장해야 함 정렬 요구를 지켜야 함 이미 할당된 블록은 수정/이동 금지 임 (그래서 압축 불가) 목표 처리량 : 단위 시간당 처리하는 요청 수 메모리 이용도 : 응용이 요청한 데이터 총량 ÷ 힙 크기 이 둘은 서로 충돌함. 빠르게 하면 알뜰하지 못하고, 알뜰하게 하려면 오래 탐색해야 함. 그 균형을 잡는 게 설계의 핵심임. 1. 블록 구조 힙 전체의 모양 [ 패딩 ][ 프롤로그 ][ 일반 블록 ][ 일반 블록 ] ... [ 에필로그 ] ↑ heap_listp 구성 설명 패딩 정렬을 맞추기 위한 빈 칸(4B) 프롤로그 크기 8B, 항상 allocated . 헤더+푸터만 있는 가짜 블록 일반 블록 malloc / free 로 생기는 블록들 에필로그 헤더만 있고 크기 0, allocated 비트 1. 힙의 끝 표지 프롤로그/에필로그를 두는 이유 연결( coalesce )할 때 현재 블록의 앞/뒤 블록 상태를 확인함. 힙 맨 앞/뒤 블록이면 이웃이 없을 수 있어서, 원래는 "이웃이 존재하는가?"를 따로 검사해야 함. 항상 allocated인 가짜 블록을 양 끝에 두면, 모든 블록에 대해 이 검사 없이 똑같은 코드로 처리됨. 에필로그의 값이 0/1 인 이유 크기 0 : 정상 블록은 최소 크기 때문에 0일 수 없음. 헤더를 읽었는데 크기가 0이면 "힙의 끝"으로 판단하고 탐색을 멈출 수 있음. alloc = 1 : 0이면 할당기가 free 블록으로 착각해서 쓰려고 할 수 있음. 절대 가용 블록으로 취급하지 않게 1로 설정함. 블록 하나의 구조 ┌─────────┬──────────────────┬─────────┐ │ 헤더 4B │ payload │ 푸터 4B │ │ size|a │ │ size|a │ └─────────┴──────────────────┴─────────┘ ↑ bp 헤더/푸터 : 블록 전체 크기(헤더+페이로드+푸터+패딩)와 할당 여부를 담음. payload : 사용자가 실제로 쓰는 공간임. int *p = malloc(20); 에서 p 가 가리키는 곳임. bp : 첫 번째 payload 바이트를 가리키는 포인터임. 블록의 시작이 아니라 payload의 시작 이라는 점이 제일 중요함. 응용 프로그램은 헤더의 존재를 모름. 할당기 내부에서 헤더에 접근할 때만 bp 에서 4바이트를 빼서 찾음. 헤더/푸터가 필요한 이유 블록이 얼마나 큰지, 사용 중인지 알아야 함. 앞뒤에 어떤 블록이 있는지 알아야 함. free 할 때 어디와 합칠지 알아야 함. 헤더 32비트를 쪼개 쓰는 법 31 3 2 1 0 ┌──────────────────────────┬──┬──┬──┐ │ block size │ 0│ 0│ a│ a=1: 사용 중, a=0: free └──────────────────────────┴──┴──┴──┘ 가능한 이유는 모든 블록의 크기가 8의 배수이기 때문 임. 32 = 0010 0000 40 = 0010 1000 48 = 0011 0000 8 = 23이라서 8의 배수는 이진수 끝 3자리가 항상 000 임. 어차피 비어 있는 자리라서 그중 최하위 비트를 "allocated" 정보로 재활용함. 예를 들어 할당된 24바이트( 0x18 ) 블록의 헤더는 0x18 | 0x1 = 0x19 , 빈 40바이트( 0x28 ) 블록의 헤더는 0x28 | 0x0 = 0x28 임. 이걸 다루는 매크로가 PACK() , GET_SIZE() , GET_ALLOC() 임. 왜 8의 배수여야 하나 → 정렬때문! malloc 이 반환한 메모리에 어떤 타입이 들어갈지 할당기는 모름. 그래서 가장 엄격한 정렬로 맞춰 둠. 정렬이 안 맞으면 느려지거나, 일부 CPU/명령어에서는 오류가 남. 이 구현은 payload 시작 주소를 8의 배수 로 맞춤. 패딩 워드를 맨 앞에 넣는 이유 패딩 없이 시작: [헤더 4B][payload] payload 시작 = 0x04 X 패딩 4B 추가: [패딩 4B][헤더 4B][payload] payload 시작 = 0x08 O 헤더가 4바이트라서, 헤더 바로 뒤의 payload를 8의 배수에 두려면 헤더가 8n+4 위치에 있어야 함. 첫 블록만 맞으면 뒤도 다 맞음. 블록 크기가 항상 8의 배수 라서 다음 헤더도 8n+4 위치가 되기 때문임. 묵시적 리스트와 최소 블록 크기 묵시적 리스트 빈 블록끼리 포인터로 연결돼 있지 않음. 헤더의 크기 필드를 따라 힙의 모든 블록을 훑어서 빈 블록을 찾음. 그래서 "묵시적"임. 장점은 단순함이고, 단점은 탐색 비용이 (할당+빈) 전체 블록 수에 비례 한다는 것임. 최소 블록 크기: 16바이트 헤더 4B + 푸터 4B + 정렬을 위한 최소 payload 8B임. 1바이트를 요청해도 16바이트 블록이 만들어짐. 할당기가 하는 일 요약 malloc() → free block을 찾아서 allocated로 변경 free() → allocated block을 free로 바꾸고 옆 free block과 합침 extend_heap() → 에필로그 자리에 새로운 free block 추가 2. memlib.c - 힙 공간 구현 (9.9.1) 실제 프로세스 힙 대신 큰 배열을 힙처럼 만들어 사용함. void *mem_sbrk(int incr) { char *old_brk = mem_brk; if ((incr < 0) || ((mem_brk + incr) > mem_max_addr)) { errno = ENOMEM; return (void *)-1; } mem_brk += incr; return (void *)old_brk; // 늘리기 전 brk를 반환 } 진짜 sbrk 와 같은 인터페이스 늘리기 전의 brk를 반환 함. 이 값이 새로 얻은 영역의 시작 주소라서 extend_heap 에서 bp 가 됨. 진짜 sbrk 와 다른 점은 힙 축소(음수 incr)를 거부 한다는 것임. free(ptr) 에는 malloc 이 반환한 포인터를 넘겨야 함. mm_free 는 bp-4 를 헤더로 보고 접근하기 때문에, 잘못된 포인터를 넘기면 엉뚱한 값을 읽어 힙이 깨질 수 있음. 3. 상수와 매크로 #define WSIZE 4 // 워드 = 헤더/푸터 크기 #define DSIZE 8 // 더블워드 = 정렬 단위 #define CHUNKSIZE (1<<12) // 힙 확장 기본 단위 (4096B) #define MAX(x, y) ((x) > (y) ? (x) : (y)) 값 만들기/읽기/쓰기 매크로 의미 PACK(size, alloc) 크기와 할당 비트를 OR해서 헤더 값을 만듦 GET(p) 주소 p 의 4바이트 읽기 PUT(p, val) 주소 p 에 4바이트 쓰기 GET_SIZE(p) GET(p) & ~0x7 → 하위 3비트를 지워서 크기만 가져옴 GET_ALLOC(p) GET(p) & 0x1 → 마지막 한 비트만 가져옴 GET / PUT 은 p 가 보통 void * 라서 역참조가 안 됨. 그래서 unsigned int * (4바이트)로 캐스팅해서 읽고 씀. 헤더/푸터가 1워드라서 4바이트 단위임. PACK 은 하위 3비트가 비어 있어서 OR만 해도 정보가 섞이지 않음. PACK(24, 1) = 0x19 , 에필로그는 PACK(0, 1) 임. 헤더 값이 33이면 이렇게 풀림. 33 = 0010 0001 GET_SIZE → 32 (하위 3비트를 지움) GET_ALLOC → 1 (사용 중) bp 로 주소 찾기 bp-4 bp bp+size-8 bp+size ↓ ↓ ↓ ↓ [ 헤더 ][ payload ................ ][ 푸터 ][ 다음 블록 헤더 ] HDRP payload 바로 앞이 헤더임. HDRP(bp) = bp - 4 FTRP 푸터 위치를 구하려면 블록 전체 크기를 알아야 해서 헤더를 읽음. FTRP(bp) = bp + GET_SIZE(HDRP(bp)) - DSIZE 숫자 예시로 보면 이렇게 됨. 주소: 100 104 120 124 [ H ][ ........ payload 16B ........ ][ F ] ↑ bp 블록 크기 24 → bp + size = 104 + 24 = 128 (다음 블록의 bp) 128 - 8 = 120 → 푸터 시작 bp + size 는 다음 블록의 bp 위치임. 여기서 8을 빼면 현재 블록의 푸터 위치가 나옴. bp가 현재 블록의 payload 시작점이라서, 블록의 시작점까지 4B, 푸터까지 4B를 빼는 것임. NEXT_BLKP 블록 전체 크기만큼 이동하면 다음 블록의 bp가 됨. bp-4 bp bp+size-4 bp+size ↓ ↓ ↓ ↓ [ 헤더 ][ payload ......... ][ 푸터 ][ 다음 헤더 ][ 다음 payload ... ↑ NEXT_BLKP(bp) = bp + size NEXT_BLKP(bp) = bp + GET_SIZE(bp - WSIZE) 헤더의 크기를 따라가는 이 동작이 묵시적 리스트 순회 의 핵심! PREV_BLKP 현재 블록의 바로 앞에는 이전 블록의 푸터가 있음. 이전 블록 현재 블록 ┌────────────────────────┐ ┌────────────────────┐ │ H │ payload │ F(20) │ │ H │ payload │ F │ └────────────────────────┘ └────────────────────┘ ↑ ↑ ↑ bp-8 bp-4 bp (이전 푸터) (현재 헤더) PREV_BLKP(bp) = bp - GET_SIZE(bp - DSIZE) 이전 블록의 푸터( bp-8 )에서 크기를 읽고, 그만큼 bp 에서 뒤로 이동하면 이전 블록의 bp 를 찾을 수 있음. 푸터가 없으면 힙을 처음부터 훑어야 함 코드를 읽을 때 주의할 점: 갱신 순서 FTRP(bp) 는 헤더에 적힌 크기 로 푸터 위치를 계산함. 그래서 place 와 coalesce 에서는 아래 순서가 중요함. 헤더를 새 크기로 먼저 바꾼 뒤 FTRP 를 부르면 → 새 크기 기준 위치 바꾸기 전에 부르면 → 옛 크기 기준 위치 순서가 틀리면 엉뚱한 주소를 덮어쓰게 됨. 4. mm_init : 초기 힙 구성 allocator가 처음 시작할 때 힙을 처음 만들어줌. mem_sbrk(4 * WSIZE) 로 16바이트 를 확보하고 이렇게 채움. 패딩(4B) - 프롤로그(헤더 4B, 푸터 4B) - 에필로그(헤더 4B) → 총 16B 오프셋: 0 4 8 12 [ 0 ][ 8/1 ] [ 8/1 ] [ 0/1 ] ↑ heap_listp 과정: 패딩 만들기 : 정렬을 위한 값 0을 씀. 프롤로그 헤더 생성 (크기 8, allocated) 프롤로그 푸터 생성 에필로그 헤더 생성 (크기 0, allocated) heap_listp 가 프롤로그 블록의 bp 를 가리키도록 +2*WSIZE 이동함. 이후 힙 순회의 출발점임. extend_heap 을 호출해서 첫 free block을 만듦. 패딩 4B + 프롤로그 헤더 4B = 8B라서 이후 블록들의 payload가 8의 배수 주소에 놓임. 5. extend_heap : 힙을 늘리고 free block 만들기 호출되는 경우 처음 allocator를 초기화할 때 ( mm_init ) malloc 할 공간이 없을 때 ( mm_malloc ) 코드 흐름 크기 맞추기 : words 가 홀수면 하나 올려서 짝수 워드(8의 배수 바이트) 로 만듦. 8바이트 정렬을 유지하려는 것임. mem_sbrk(size) : 힙의 끝을 size 만큼 늘리고, 새로 확보한 영역의 시작 주소 를 bp 로 받음. 새 블록의 헤더, 푸터 를 PACK(size, 0) 으로 씀. 새 블록 바로 뒤에 새 에필로그 를 만듦. coalesce(bp) 로 앞 블록이 비어 있으면 합침. 핵심: 왜 HDRP(bp) 가 맞나 확장 전: [ ... ][ 에필로그 ] 확장 후: [ ... ][ 에필로그 ][ 새 공간 ........ ] ↑ ↑ bp-4 bp (mem_sbrk가 반환한 옛 brk) mem_sbrk 가 반환한 bp 는 기존 에필로그 바로 뒤 임. 그래서 bp - 4 가 기존 에필로그 헤더 자리 이고, 거기에 새 free block의 헤더를 덮어씀. 기존 에필로그가 새 블록의 헤더가 되는 것임. 새로 확보한 영역의 맨 마지막 워드에 새 에필로그를 만듦. 확장 후 정리: [ ... ][ 헤더 | ...... free ...... | 푸터 ][ 새 에필로그 ] ↑ ↑ 옛 에필로그 자리 HDRP(NEXT_BLKP(bp)) 새 에필로그 위치는 이렇게 구함. PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)); 방금 쓴 헤더의 크기를 이용해서 다음 블록의 bp 를 구하고, 그 헤더 자리가 새 에필로그가 됨. ex) 초기 힙이 [패딩(0~3)][프롤로그(4~11)][에필로그(12~15)] 일 때 extend_heap(1024) 를 호출하면: size = 4096 , mem_sbrk(4096) 이 16 을 반환하고 bp = 16 임. HDRP(bp) = 12 에 4096/0 을 씀 (옛 에필로그 자리). FTRP(bp) = 16 + 4096 - 8 = 4104 에 푸터를 씀. HDRP(NEXT_BLKP(bp)) = 4108 에 새 에필로그 0/1 을 씀. 왜 마지막에 coalesce 를 부르나 힙이 늘기 전에 마지막 블록이 free였다면 새 free block과 연속된 free 블록 이 생김. 확장 전: [P][A a][B f][E] 확장 후: [P][A a][B f][새로운 f][E] ← free 두 개가 붙음 coalesce: [P][A a][ B + 새 f ][E] ← 하나로 합침 초기화 때는 앞이 프롤로그(allocated)라서 합칠 게 없음. 6. mm_malloc : 블록 할당 흐름은 두 질문으로 요약됨. 몇 바이트 블록이 필요한가? 그 크기를 담는 빈 블록이 있는가? ex) malloc(20) │ ▼ asize 계산 │ ▼ find_fit() ↙ ↘ 찾음 못 찾음 │ │ ▼ ▼ place() extend_heap() │ │ ▼ ▼ bp 반환 place() │ ▼ bp 반환 (1) size와 asize size : 사용자가 요청한 데이터 크기 asize : allocator가 실제로 만들 블록 전체 크기 규칙) size 가 8 이하면 asize = 16 (최소 블록 크기) 그 외에는 size + 8 (헤더+푸터)을 8의 배수로 올림 요청 size 계산 asize 1 ~ 8 최소 블록 16 9 9+8=17 → 올림 24 20 20+8=28 → 올림 32 size == 0 이면 NULL 을 반환함. (2) find_fit : 맞는 빈 블록 찾기 asize 이상의 free block이 있는지 heap_listp 에서 시작해 힙을 훑음. 못 찾으면 NULL 을 반환하고, 그러면 힙을 확장함. 탐색 종료 조건 -> 에필로그(크기 0) 만나는 것. 배치 정책 (9.9.7) 정책 방식 장점 단점 first fit 처음부터 훑어 처음 맞는 블록 큰 블록이 뒤쪽에 남음 앞쪽에 작은 조각(splinter)이 쌓여 큰 요청의 탐색이 느려짐 next fit 직전 탐색이 끝난 곳부터 앞쪽에 조각이 많아도 빠를 수 있음 일부 연구에서 first fit보다 이용도가 나쁨 best fit 전부 훑어 가장 작게 맞는 블록 이용도가 대체로 가장 좋음 단순 리스트에서는 힙 전체 를 훑어야 함 이 구현은 first fit임. first fit은 의도해서 큰 블록을 뒤에 남기는 게 아니라, 앞쪽부터 쓰고 쪼개다 보니 생기는 부수 효과임. best fit의 단점은 나중에 나오는 분리 빈 리스트(9.9.14) 로 해결할 수 있음. 크기 클래스별로 리스트를 나눠서 전체를 훑지 않고도 best fit에 가까운 결과를 얻음. (3) place : 배치와 분할 찾은 블록이 필요한 것보다 클 때 선택지 1. 현재 블록 크기 - asize >= 최소 블록 크기(16) → 앞부분은 할당, 뒷부분은 새 free 블록으로 남김 (분할) 2. 아니면 → 통째로 사용 (남는 부분이 너무 작아서 블록을 못 만듦) 분할: [ 4048 free ] → [ 32 할당 ][ 4016 free ] 통째로 사용 : 단순하고 빠르지만 내부 단편화 가 생김. 분할 : 공간을 아끼지만 헤더/푸터를 하나 더 만들어야 함. 분할 기준이 16인 이유는 최소 블록 크기가 16이라 그보다 작은 나머지는 블록이 될 수 없기 때문임. (4) 못 찾으면 힙 확장 (9.9.9) extendsize = MAX(asize, CHUNKSIZE); 작은 요청마다 조금씩 sbrk 하면 비효율적이라 기본 4096바이트 씩 한 번에 늘림. 요청이 4096보다 크면(예: asize = 5008 ) 필요한 만큼 늘림. 책 본문은 "먼저 인접 빈 블록 연결을 시도하고, 안 되면 sbrk "라고 설명함. 이 구현은 free 마다 즉시 연결하므로 이미 최대한 합쳐져 있어서 바로 extend_heap 으로 감. 늘린 뒤에는 새 free block에 place 하고 bp 를 반환함. 이 흐름에서 place 는 각 경로에서 한 번씩만 호출됨. 7. mm_free 와 coalesce mm_free 블록의 alloc 비트를 1 → 0 으로 바꿈 (헤더와 푸터 둘 다) coalesce 를 호출해서 free 블록이 연속으로 붙어 있지 않게 해줌 연결 시점: 즉시 vs 지연 (9.9.10) 연결을 안 하면 거짓 단편화 가 생김. 실제로는 붙어 있는 빈 블록인데 별개 블록으로 취급해서 큰 공간으로 못 쓰게 됨. [3워드 빈 블록][3워드 빈 블록] → 각각 3워드로 관리 → 4워드 요청 시 사용 불가 합치면 [ 6워드 빈 블록 ] → 4워드 요청 가능 즉시 연결 지연 연결 시점 free 시점에 바로 병합 free 는 상태만 바꾸고, 나중에 malloc 이 빈 블록을 못 찾을 때 병합 장점 구현이 단순, 외부 단편화를 빠르게 줄임 불필요한 병합/분할을 줄임, free 가 빠름 단점 할당/해제를 반복하면 스래싱 (합쳤다가 바로 다시 쪼갬) 병합이 필요한 시점에 추가 작업 필요 교재의 코드 구현은 즉시 연결 을 사용 coalesce : 이웃의 상태로 네 가지 경우 prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(bp))); // 이전 블록: 푸터로 확인 next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp))); // 다음 블록: 헤더로 확인 Case [이전][현재][다음] 결과 1 [ a ] [ f ] [ a ] 합칠 것 없음 (현재만 free 표시) 2 [ a ] [ f ] [ f ] 현재 + 다음 합침 3 [ f ] [ f ] [ a ] 이전 + 현재 합침, bp 를 이전 블록으로 이동 4 [ f ] [ f ] [ f ] 셋 다 합침, bp 를 이전 블록으로 이동 합칠 때의 규칙: 합쳐진 덩어리의 맨 앞 헤더 와 맨 뒤 푸터 만 새 크기로 고침. 중간에 끼어 있던 옛 헤더/푸터는 지우지 않아도 되고, 그냥 내부 데이터로 남아서 무시됨. Case 4: [H 64][...][F 64] [H 32][...][F 32] [H 48][...][F 48] ↓ [H 144][........................................][F 144] ↑ 이전 블록의 헤더 다음 블록의 푸터 ↑ Case 합쳐진 블록의 헤더 합쳐진 블록의 푸터 2 현재 헤더 다음 블록의 푸터 3 이전 블록의 헤더 현재 푸터 4 이전 블록의 헤더 다음 블록의 푸터 Case 3, 4는 합쳐진 블록의 시작이 이전 블록으로 옮겨지므로
velog
『실무로 통하는 타입스크립트』 Boolean 생성자로 null/undefined 제거하기 배열에서 null 종류의 값을 거르는 Boolean 생성자를 사용하려는데, TypeScript는 여전히 null 과 undefined 를 포함한 같은 타입을 반환한다. const array = [1, 2, 3, undefined, 4, null]; const filtered = array.filter((val) => !!val); 직접 확인한 결과, filtered 의 타입은 여전히 (number | null | undefined)[] 다. 런타임에서는 실제로 걸러졌어도, 타입 시스템은 필터 콜백의 로직까지 분석하지 못해서 원본과 같은 타입을 그대로 돌려준다. 해결 : 선언 합치기로 Array 의 filter 메서드를 오버로드한다. declare global { interface Array<T> { filter(predicate: BooleanConstructor): NonNullable<T>[]; } interface ReadonlyArray<T> { filter(predicate: BooleanConstructor): NonNullable<T>[]; } } // BooleanConstructor는 Boolean 생성자 자체의 타입이다 (typeof Boolean). // 즉 predicate 자리에 Boolean을 "그대로" 넘긴 특정 호출만 이 오버로드가 잡아낸다. const filtered2 = array.filter(Boolean); 직접 검증한 결과, filtered2 는 정확히 number[] 로 좁혀졌다. falsy 값까지 제거하는 Truthy BooleanConstructor 는 falsy한 값( "" , false , 0 , 0n , null , undefined )을 전부 거른다. 그런데 NonNullable<T> 는 null / undefined 만 제거할 뿐, 나머지 falsy 값( 0 , false , "" )은 타입에 그대로 남는다. type Truthy<T> = T extends "" | false | 0 | 0n ? never : T; declare global { interface Array<T> { filter(predicate: BooleanConstructor): Truthy<NonNullable<T>>[]; } interface ReadonlyArray<T> { filter(predicate: BooleanConstructor): Truthy<NonNullable<T>>[]; } } const nullOrOne: Array<0 | 1> = [0, 1, 0, 1]; const onlyOnes = nullOrOne.filter(Boolean); // onlyOnes: 1[] 직접 확인한 결과, 0 | 1 에서 0 이 제거되고 1[] 만 남았다. 라이브러리 타입 정의 패치하기 — 모듈 선언 합치기 Preact나 React 같은 라이브러리를 사용 중인데, 타입 정의가 최신 기능을 포함하지 않을 때가 있어 패치하고 싶다. 해결 : 모듈과 인터페이스 수준에서 선언 합치기를 한다. @types 폴더를 만들고 jsx.d.ts 파일을 추가한다. compilerOptions.types 에 해당 경로를 설정한다. 원하는 정의를 추가한다. import "react"; declare module "react" { interface ImgHTMLAttributes<T> extends HTMLAttributes<T> { loading?: "lazy" | "eager" | "auto"; alt: string; } } declare / module / namespace의 차이 키워드 역할 declare "이 코드는 어딘가에 실제로 존재하지만, 그 구현은 여기 없다"는 선언. 타입 정보만 컴파일러에 알려준다 declare module "이름" 특정 모듈 (파일 또는 패키지)의 타입을 선언하거나 확장한다 declare namespace 전역에 네임스페이스 (이름 묶음)를 선언한다. 레거시 JS 라이브러리(jQuery 등)처럼 전역 변수 하나에 여러 기능을 매달아 쓰던 패턴을 타이핑할 때 주로 쓴다 declare global 모듈 안에서 전역 스코프 를 확장한다 그 밖에 declare const (변수), declare function (함수), declare class (클래스)도 있다. 이들을 묶어 주변 선언(ambient declaration) 이라 부른다. 아직 지원되지 않는 브라우저 기능 타이핑하기 ResizeObserver 같은 브라우저 기능을 썼는데, 현재 TypeScript 설정에서 해당 기능을 사용할 수 없다. 해결 : 전역 네임스페이스에 사용자 정의 타입 정의를 추가한다. lib.dom.d.ts 업데이트를 기다릴 수 없다면 직접 타입을 추가할 수 있다. // resize-observer.d.ts declare var ResizeObserver: { prototype: ResizeObserver; new (callback: ResizeObserverCallback): ResizeObserver; }; 어디에서나 사용하려면 declare global 로 감싼다. declare global { var ResizeObserver: { prototype: ResizeObserver; new (callback: ResizeObserverCallback): ResizeObserver; }; } resize-observer.d.ts 를 @types 폴더에 넣고 typeRoots , include 에 경로를 설정한다. 존재하지 않을 수도 있다는 걸 타입으로 표현하기 대상 브라우저에서 ResizeObserver 를 아직 사용할 수 없을 가능성이 있다면, 정의되지 않은 상태( undefined )일 수 있다는 걸 타입에 포함시킨다. declare global { var ResizeObserver: | { prototype: ResizeObserver; new (callback: ResizeObserverCallback): ResizeObserver; } | undefined; } 타입에 | undefined 를 추가하면, "이 전역 객체는 없을 수도 있다"는 정보가 컴파일러에 전달된다. 그래서 체크 없이 바로 쓰면 에러가 나고, 런타임에 실제로 존재하는지 확인한 뒤에만 쓰도록 강제된다. const x = ResizeObserver.prototype; // TS18048: 'ResizeObserver' is possibly 'undefined' if (typeof ResizeObserver !== "undefined") { const x = new ResizeObserver((entries) => {}); // 통과 } 직접 검증한 결과, 체크 없는 접근은 정확히 이 에러로 막히고, typeof 체크를 거치면 정상적으로 좁혀져 통과한다. "객체를 사용할 수 있는지 확인할 수 있다"는 말은 이 런타임 존재 여부 검사를 타입 시스템이 강제한다 는 뜻이다. 엠비언트 선언 파일을 TypeScript가 인식하지 못할 때 확인할 것 include 속성에 @types 폴더 경로가 포함되어 있는지 확인한다. 여기 포함돼 있어야 컴파일러가 그 폴더의 .d.ts 파일들을 읽어 타입 검사 대상으로 삼는다 ( "파싱한다" 는 이 과정, 즉 폴더 안의 선언 파일들을 읽어 들여 분석한다는 뜻이다). 엠비언트 파일을 types 나 typeRoots 에 추가한다. 엠비언트 파일 끝에 export {} 를 추가하면 TypeScript가 그 파일을 모듈로 인식한다. 직접 확인한 결과, export {} 가 없으면 declare global 자체가 TS2669: Augmentations for the global scope can only be directly nested in external modules or ambient module declarations 에러로 막힌다. declare global 은 모듈 안에서만 쓸 수 있는 문법이기 때문이다. 번들러로 불러온 비-JS 파일 타이핑하기 (.css, 이미지 등) 웹팩 같은 번들러로 JavaScript에서 .css 나 이미지 같은 파일을 불러왔는데, TypeScript는 이러한 파일을 인식하지 못한다. 해결 : 파일명 확장자에 기반해 모듈을 전역으로 선언한다. TypeScript는 환경에 있거나 도구를 통해 접근할 수 있는 모듈에도 엠비언트 모듈 선언 을 지원한다 ( url , http , path 같은 Node 주요 내장 모듈 등). 와일드카드 패턴에도 사용할 수 있다. declare module "*.css" { interface IClassNames { [className: string]: string; } const classNames: IClassNames; export default classNames; } 임포트하려는 모든 .css 파일을 이 선언이 인식한다. 다만 자동완성에서 정확한 클래스 이름까지는 알 수 없다. NPM 패키지를 추가로 설치하면 타입 파일을 자동으로 생성해 해결할 수 있다. 이 밖에 *.mdx 를 선언하면 JSX 파일에서 컴포넌트로 사용할 수 있다. 앰비언트 모듈을 사용하려면 @types 폴더를 만드는 게 좋다. 이 폴더에 모듈 정의가 포함된 .d.ts 파일을 얼마든지 추가할 수 있다. typeRoots 옵션으로 @types 경로를 설정한다.
Score: 56.98Confidence: 54%
Score: 54.4Confidence: 49%
Score: 54.4Confidence: 49%