mirror of
https://github.com/wanghongenpin/proxypin.git
synced 2026-06-01 17:15:48 +08:00
fix(macos,process_info): address Copilot review feedback
- Add 30s (host:port) -> pid cache in ProcessInfoUtils so the synchronous libproc scan stays off the request hot path for keep-alive flows (typical HTTP client reuses the same source port across requests in a connection). - Lift sockView ByteData out of the inner fd loop so the buffer wrapper is reused across all fds in a scan (saves per-fd allocations). - Bail out of the scan after 16 consecutive proc_pidfdinfo size mismatches, in case a future macOS bumps the socket_fdinfo layout -- avoids wasted syscalls instead of scanning every fd just to return null at the end. Re-verified end-to-end on macOS 26.4: 500 concurrent curl, 0 fork leaks, 9099 freed immediately on app exit, no errors in logs.
This commit is contained in:
@@ -38,6 +38,13 @@ void main() async {
|
||||
class ProcessInfoUtils {
|
||||
static final processInfoCache = ExpiringCache<String, ProcessInfo>(const Duration(minutes: 5));
|
||||
|
||||
// (host:port) -> pid short cache. Keeps the FFI / Process.run lookup off
|
||||
// the request hot path for the typical HTTP keep-alive case where many
|
||||
// requests share a single client TCP connection (and thus a single
|
||||
// remote socket address). Greatly reduces how often the synchronous
|
||||
// libproc scan runs on the main isolate.
|
||||
static final _pidCache = ExpiringCache<String, int>(const Duration(seconds: 30));
|
||||
|
||||
static Future<ProcessInfo?> getProcessByPort(InetSocketAddress socketAddress, String cacheKeyPre) async {
|
||||
try {
|
||||
if (Platform.isAndroid) {
|
||||
@@ -51,8 +58,13 @@ class ProcessInfoUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
var pid = await _getPid(socketAddress);
|
||||
if (pid == null) return null;
|
||||
var addrKey = "${socketAddress.host}:${socketAddress.port}";
|
||||
var pid = _pidCache.get(addrKey);
|
||||
if (pid == null) {
|
||||
pid = await _getPid(socketAddress);
|
||||
if (pid == null) return null;
|
||||
_pidCache.set(addrKey, pid);
|
||||
}
|
||||
|
||||
String cacheKey = "$cacheKeyPre:$pid";
|
||||
var processInfo = processInfoCache.get(cacheKey);
|
||||
|
||||
@@ -98,6 +98,16 @@ class MacosProcessInfo {
|
||||
|
||||
final pidBuf = calloc<Uint8>(pidBufSize);
|
||||
final sockBuf = calloc<Uint8>(_kSizeofSocketFdInfo);
|
||||
// Reuse the same ByteData view across all fds; the underlying native
|
||||
// buffer is overwritten in place by each proc_pidfdinfo call.
|
||||
final sockView = ByteData.sublistView(sockBuf.asTypedList(_kSizeofSocketFdInfo));
|
||||
|
||||
// If proc_pidfdinfo keeps returning a size smaller than expected, the
|
||||
// struct layout has changed (e.g. a future macOS bumped the size) and
|
||||
// continuing the scan can't possibly find anything. Bail out early
|
||||
// after enough consecutive mismatches to avoid wasting syscalls.
|
||||
var consecutiveLayoutMismatch = 0;
|
||||
const layoutMismatchThreshold = 16;
|
||||
|
||||
try {
|
||||
final actual = _procListPids(_kProcAllPids, 0, pidBuf.cast(), pidBufSize);
|
||||
@@ -107,6 +117,7 @@ class MacosProcessInfo {
|
||||
|
||||
for (final pid in pidView) {
|
||||
if (pid <= 0) continue;
|
||||
if (consecutiveLayoutMismatch >= layoutMismatchThreshold) break;
|
||||
|
||||
final fdSize = _procPidInfo(pid, _kProcPidListFds, 0, nullptr, 0);
|
||||
if (fdSize <= 0) continue;
|
||||
@@ -127,9 +138,12 @@ class MacosProcessInfo {
|
||||
final fd = fdView.getInt32(entryOff + _kOffProcFd, Endian.host);
|
||||
|
||||
final n = _procPidFdInfo(pid, fd, _kProcPidFdSocketInfo, sockBuf.cast(), _kSizeofSocketFdInfo);
|
||||
if (n < _kSizeofSocketFdInfo) continue;
|
||||
if (n < _kSizeofSocketFdInfo) {
|
||||
consecutiveLayoutMismatch++;
|
||||
continue;
|
||||
}
|
||||
consecutiveLayoutMismatch = 0;
|
||||
|
||||
final sockView = ByteData.sublistView(sockBuf.asTypedList(_kSizeofSocketFdInfo));
|
||||
final soiKind = sockView.getInt32(_kOffSoiKind, Endian.host);
|
||||
if (soiKind != _kSockInfoTcp) continue;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user