You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决PJSUA C#(DLL PINVOKE)中LogWriter释放时的System.AccessViolationException

解决方案

核心原因

当你将自定义LogWriter赋值给epConfig.logConfig.writer后,PJSUA2的非托管代码会接管该对象的内存所有权。但SWIG生成的默认Dispose方法仍会尝试调用delete_LogWriter释放内存,导致重复释放或访问已被非托管代码销毁的内存,从而抛出AccessViolationException。


方案1:重写Dispose方法阻止.NET释放非托管内存

在自定义的MyLogWriter类中重写Dispose方法,跳过SWIG生成的delete_LogWriter调用:

public class MyLogWriter : LogWriter
{
    protected override void Dispose(bool disposing)
    {
        lock (this)
        {
            if (swigCPtr.Handle != IntPtr.Zero)
            {
                // 标记不再拥有内存所有权,避免触发非托管delete操作
                swigCMemOwn = false;
                // 重置句柄,防止后续重复处理
                swigCPtr = new HandleRef(null, IntPtr.Zero);
            }
            // 不要调用base.Dispose(disposing),避免执行原有的delete逻辑
        }
    }
}

方案2:手动转移内存所有权给非托管代码

在将LogWriter赋值给配置后,直接修改swigCMemOwn字段,让.NET放弃内存管理权限:

MyLogWriter writer = new MyLogWriter();
epConfig.logConfig.writer = writer;
// 转移所有权至非托管代码,.NET不再尝试释放
writer.swigCMemOwn = false;

方案3:调整清理顺序确保非托管代码先释放

在应用关闭时,先让Endpoint停止使用LogWriter,再执行销毁和释放操作:

// 第一步:移除Endpoint对LogWriter的引用
epConfig.logConfig.writer = null;
// 第二步:销毁PJSUA2库
ep.libdestroy();
// 第三步:安全释放托管侧的LogWriter(如果所有权仍在.NET)
writer.Dispose();

额外注意事项

  • 如果修改SWIG接口文件,可以通过%nodefaultdtor禁用默认析构函数,或用%delobject明确指定内存释放的责任方,从根源避免冲突。
  • 确保所有PJSUA2对象的释放顺序符合官方文档要求:先销毁会话、呼叫等资源,再调用ep.libdestroy(),最后处理全局配置对象。

内容的提问来源于stack exchange,提问作者lukas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 21:35:35