Skip to content

Commit 046bd18

Browse files
committed
post
1 parent dc063e8 commit 046bd18

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
title: "Hammerspoon eventtap이 몇 분 후 멈추는 이유"
3+
slug: hammerspoon-eventtap-gc
4+
created: 2026-02-07
5+
category: etc
6+
type: [til]
7+
tags: []
8+
---
9+
10+
## 증상
11+
12+
Hammerspoon에서 `hs.eventtap`으로 키보드 이벤트를 가로채는 설정을 했는데, 몇 분만 지나면 동작이 완전히 멈추는 현상이 발생했다.
13+
메뉴바에서 Reload Config를 누르면 다시 동작하지만, 또 몇 분 후에 멈추는 것이 반복되었다.
14+
15+
문제가 된 코드는 다음과 같다.
16+
17+
```lua
18+
-- layers.lua
19+
local layerTap = eventtap.new({ types.keyDown, types.keyUp }, function(e)
20+
-- 콜백 로직 ...
21+
end)
22+
23+
layerTap:start()
24+
```
25+
26+
## 원인: Lua 가비지 컬렉션
27+
28+
`layerTap`이 파일 스코프의 **로컬 변수**이다. `require("layers")`로 이 파일이 실행된 후, `layerTap`을 참조하는 곳이 없어진다.
29+
30+
콜백 클로저는 `activeLayer`, `layers` 같은 다른 변수만 캡처하고, `layerTap` 자체는 참조하지 않는다. Lua의 클로저는 실제로 참조하는 upvalue만 캡처하기 때문이다.
31+
32+
결과적으로 `layerTap`은 어디에서도 참조되지 않는 상태가 되고, Lua GC가 이 객체를 수거하면 eventtap이 파괴되어 동작이 멈추는 것이다.
33+
GC 타이밍이 비결정적이기 때문에 "몇 분 후에 멈춘다"는 증상으로 나타난다.
34+
35+
## 해결
36+
37+
`layerTap`이 GC되지 않도록 강한 참조를 유지하면 된다.
38+
39+
```lua
40+
-- layers.lua
41+
local layerTap = eventtap.new({ types.keyDown, types.keyUp }, function(e)
42+
-- 콜백 로직 ...
43+
end)
44+
45+
layerTap:start()
46+
47+
return layerTap
48+
```
49+
50+
```lua
51+
-- init.lua
52+
_G.layerTap = require("layers")
53+
```
54+
55+
`_G`는 Lua의 글로벌 테이블이다. 여기에 저장하면 프로그램이 살아있는 동안 GC되지 않는다.
56+
57+
## 교훈
58+
59+
Hammerspoon에서 `hs.eventtap`, `hs.timer` 등 장기 실행 객체를 만들 때는 반드시 GC되지 않도록 참조를 유지해야 한다. 로컬 변수에만 담아두면 GC 대상이 되어 예고 없이 멈출 수 있다.

posts/etc/tmux-server-socket.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ tags: []
1111

1212
tmux는 단순한 터미널 멀티플렉서처럼 보이지만, 내부적으로는 **서버-클라이언트 구조**로 동작한다.
1313

14-
```
14+
```txt
1515
terminal ──socket──▶ tmux server ─┬─ session A ─┬─ window 1 ─┬─ pane 1
1616
(client) │ │ └─ pane 2
1717
│ └─ window 2 ─── pane 1

0 commit comments

Comments
 (0)