我正在使用 CFNetwork API 来检测操作系统代理设置。我的设置很大程度上基于此: https ://github.com/adobe/chromium/blob/master/net/proxy/proxy_resolver_mac.cc 这与此几乎相同: https ://developer.apple.com/ library/archive/samplecode/CFProxySupportTool/Introduction/Intro.html
我使用 CFNetworkCopyProxiesForURL 来获取代理列表,对于 PAC 类型,使用 CFNetworkExecuteProxyAutoConfigurationURL 来获取并执行 PAC 脚本,立即在当前线程上运行 run loop,这已经不在 ui 线程上。
这一切都正常工作,我仔细梳理了确保我遵循创建规则以正确发布结果。但是,在使用 Xcode 工具时,我看到 std::shared_ptrs 到 PAC::PACClient 被 _CFNetworkExecuteProxyAutoConfigurationURLDelegated 泄露。由于该对象从未暴露给我,我不确定如何控制它的释放,但它正在泄漏。这只是获取 PAC 文件的问题,显式代理不会泄漏。我已经尝试在所有 CFDictionaries 上添加冗余的 CFRelease 调用,并且向我展示了这些调用是否被过度保留,但这对 PACClient 泄漏没有影响。
这是在 Mac 上的一个 cpp 文件中,而不是目标 C,在一个启用了 ARC 的项目中。
有没有人遇到过这种泄漏并知道如何防止它?
下面是执行查找的代码片段,与上述项目中的所有步骤相同。
struct PACRequestInfo {
CFURLRef url; // Caller gets this from a dictionary, doesn't need release
CFURLRef scriptURL; // Caller gets this from a dictionary, doesn't need release
CFMutableArrayRef proxies; // Reference to a dictionary that is released by the caller
};
void resultCallback(void* client, CFArrayRef proxies, CFErrorRef error) {
// Error handling removed for brevity
if (CFTypeRef* resultPtr = (CFTypeRef*) client)
*resultPtr = CFRetain(proxies);
CFRunLoopStop(CFRunLoopGetCurrent());
}
// Provided PACRequestInfo is created on the stack by the caller
void doPACRequest(const PACRequestInfo& info) {
CFTypeRef result = nullptr;
CFStreamClientContext context = { 0, &result, nullptr, nullptr, nullptr };
// Scoped ptr not shown but just calls CFRelease on destruction
CFScopedPtr<CFRunLoopSourceRef> runLoopSource(CFNetworkExecuteProxyAutoConfigurationURL(info.scriptURL, info.url, resultCallback, &context));
if (runLoopSource) {
const static CFStringRef kPrivateRunLoopMode = CFSTR("myprivateloop");
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kPrivateRunLoopMode);
CFRunLoopRunInMode(kPrivateRunLoopMode, 1.0e10, false);
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource, kPrivateRunLoopMode);
if (result && CFGetTypeID(result) == CFArrayGetTypeID()) {
CFArrayRef resultArray = (CFArrayRef) result;
CFArrayAppendArray(info.proxies, resultArray, CFRangeMake(0, CFArrayGetCount(resultArray)));
}
}
// Retain was called on this value during ResultCallback.
if (result) {
CFRelease(result);
}
}