C/C++中内存是一个很难处理的事情,正如强项就是弱项,强大的地方也是致命的地方。

内存不释放就会泄漏,多次释放就会段错误,越界更恐怖。

不释放和多次释放都可以用SrsAutoFree规避,越界就需要工具和经验的问题。

释放和多次释放,原因是内存或者对象的生命周期过程,譬如在一个while循环中,有些时候要释放,有些时候continue就好,就容易出问题。

真的需要活N久的对象吗?很少。大部分的作用域在当前函数和子函数,局部变量就可以搞定,是的,有些时候就是没有办法用局部变量,譬如由一个函数收取的包,在当前函数就需要释放。

考虑下面的逻辑:

[cpp] view plaincopy
  1. int SrsClient::publish(SrsSource* source, bool is_fmle)
  2. {
  3. int ret = ERROR_SUCCESS;
  4. SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER);
  5. while (true) {
  6. // switch to other st-threads.
  7. st_usleep(0);
  8. SrsCommonMessage* msg = NULL;
  9. if ((ret = rtmp->recv_message(&msg)) != ERROR_SUCCESS) {
  10. srs_error("recv identify client message failed. ret=%d", ret);
  11. return ret;
  12. }
  13. SrsAutoFree(SrsCommonMessage, msg, false);
  14. pithy_print.set_age(msg->header.timestamp);
  15. // reportable
  16. if (pithy_print.can_print()) {
  17. srs_trace("<- clock=%u, time=%"PRId64", obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",
  18. (int)srs_get_system_time_ms(), pithy_print.get_age(), rtmp->get_send_bytes(), rtmp->get_recv_bytes(), rtmp->get_send_kbps(), rtmp->get_recv_kbps());
  19. }
  20. // process audio packet
  21. if (msg->header.is_audio() && ((ret = source->on_audio(msg)) != ERROR_SUCCESS)) {
  22. srs_error("process audio message failed. ret=%d", ret);
  23. return ret;
  24. }
  25. // process video packet
  26. if (msg->header.is_video() && ((ret = source->on_video(msg)) != ERROR_SUCCESS)) {
  27. srs_error("process video message failed. ret=%d", ret);
  28. return ret;
  29. }
  30. // process onMetaData
  31. if (msg->header.is_amf0_data() || msg->header.is_amf3_data()) {
  32. if ((ret = msg->decode_packet()) != ERROR_SUCCESS) {
  33. srs_error("decode onMetaData message failed. ret=%d", ret);
  34. return ret;
  35. }
  36. SrsPacket* pkt = msg->get_packet();
  37. if (dynamic_cast<SrsOnMetaDataPacket*>(pkt)) {
  38. SrsOnMetaDataPacket* metadata = dynamic_cast<SrsOnMetaDataPacket*>(pkt);
  39. if ((ret = source->on_meta_data(msg, metadata)) != ERROR_SUCCESS) {
  40. srs_error("process onMetaData message failed. ret=%d", ret);
  41. return ret;
  42. }
  43. srs_trace("process onMetaData message success.");
  44. continue;
  45. }
  46. srs_trace("ignore AMF0/AMF3 data message.");
  47. continue;
  48. }
  49. // process UnPublish event.
  50. if (msg->header.is_amf0_command() || msg->header.is_amf3_command()) {
  51. if ((ret = msg->decode_packet()) != ERROR_SUCCESS) {
  52. srs_error("decode unpublish message failed. ret=%d", ret);
  53. return ret;
  54. }
  55. // flash unpublish.
  56. if (!is_fmle) {
  57. srs_trace("flash publish finished.");
  58. return ret;
  59. }
  60. SrsPacket* pkt = msg->get_packet();
  61. if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {
  62. SrsFMLEStartPacket* unpublish = dynamic_cast<SrsFMLEStartPacket*>(pkt);
  63. return rtmp->fmle_unpublish(res->stream_id, unpublish->transaction_id);
  64. }
  65. srs_trace("ignore AMF0/AMF3 command message.");
  66. continue;
  67. }
  68. }
  69. return ret;
  70. }

从RTMP协议栈拿到包后,使用在这个作用域一定会释放,所以使用AutoFree就可以保证只释放一次,而且一定释放一次。

AutoFree实现很可靠,用C++的构造和析构,以及宏定义就可以搞定。

  1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
/*
The MIT License (MIT)
Copyright (c) 2013 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SRS_CORE_AUTO_FREE_HPP
#define SRS_CORE_AUTO_FREE_HPP
/*
#include <srs_core_auto_free.hpp>
*/
#include <srs_core.hpp>
/**
* auto free the instance in the current scope.
*/
#define SrsAutoFree(className, instance, is_array) \
__SrsAutoFree<className> _auto_free_##instance(&instance, is_array)
template<class T>
class __SrsAutoFree
{
private:
T** ptr;
bool is_array;
public:
/**
* auto delete the ptr.
* @is_array a bool value indicates whether the ptr is a array.
*/
__SrsAutoFree(T** _ptr, bool _is_array){
ptr = _ptr;
is_array = _is_array;
}
virtual ~__SrsAutoFree(){
if (ptr == NULL || *ptr == NULL) {
return;
}
if (is_array) {
delete[] *ptr;
} else {
delete *ptr;
}
*ptr = NULL;
}
};
#endif

来自CODE的代码片
srs_core_auto_free.hpp

对比以下代码,没有使用auto free模式:

[cpp] view plaincopy
  1. // ignore when no messages.
  2. int count = (int)msgs.size();
  3. if (msgs.empty()) {
  4. continue;
  5. }
  6. // all msgs to forward.
  7. int i = 0;
  8. for (i = 0; i < count; i++) {
  9. SrsSharedPtrMessage* msg = msgs[i];
  10. msgs[i] = NULL;
  11. // we erased the sendout messages, the msg must not be NULL.
  12. srs_assert(msg);
  13. ret = client->send_message(msg);
  14. if (ret != ERROR_SUCCESS) {
  15. srs_error("forwarder send message to server failed. ret=%d", ret);
  16. // convert the index to count when error.
  17. i++;
  18. break;
  19. }
  20. }
  21. // clear sendout mesages.
  22. if (i < count) {
  23. srs_warn("clear forwarded msg, total=%d, forwarded=%d, ret=%d", count, i, ret);
  24. } else {
  25. srs_info("clear forwarded msg, total=%d, forwarded=%d, ret=%d", count, i, ret);
  26. }
  27. msgs.erase(msgs.begin(), msgs.begin() + i);
  28. if (ret != ERROR_SUCCESS) {
  29. break;
  30. }

使用auto free模式后:

[cpp] view plaincopy
  1. // ignore when no messages.
  2. if (count <= 0) {
  3. srs_verbose("no packets to forward.");
  4. continue;
  5. }
  6. SrsAutoFree(SrsSharedPtrMessage*, msgs, true);
  7. // all msgs to forward.
  8. for (int i = 0; i < count; i++) {
  9. SrsSharedPtrMessage* msg = msgs[i];
  10. srs_assert(msg);
  11. msgs[i] = NULL;
  12. if ((ret = client->send_message(msg)) != ERROR_SUCCESS) {
  13. srs_error("forwarder send message to server failed. ret=%d", ret);
  14. return ret;
  15. }
  16. }

如下图:

SrsAutoFree模式,避免内存泄漏和错误相关推荐

  1. macOS Monterey新问题:“内存泄漏”,应用后台运行消耗上百 GB 内存

    未来软件园11 月 2 日消息,据 MacRumors 报道,最近升级到 macOS Monterey 的一些用户遇到了一个称为"内存泄漏"的错误,在这种情况下,特定的 macOS ...

  2. 初入职常见问题:弱网络环境构造、压力测试、内存泄漏、性能持续优化工具

    文章参考自: 作者:helloworlds 链接:https://zhuanlan.zhihu.com/p/21348220 来源:知乎 弱网络环境的构造 traffic control traffi ...

  3. 使用memwatch跟踪linux内存泄漏

    参考: http://blog.csdn.net/kehyuanyu/article/details/25217907 http://blog.sina.com.cn/s/blog_590be5290 ...

  4. Android性能优化之利用强大的LeakCanary检测内存泄漏及解决办法

    本篇文章主要介绍了Android性能优化之利用LeakCanary检测内存泄漏及解决办法,有兴趣的同学可以了解一下. 目录 前言 什么是内存泄漏? 内存泄漏造成什么影响? 什么是LeakCanary? ...

  5. Linux启动检测内存条错误,linux检测程序内存泄漏和内存错误

    在linux的开发程序的时候,可以很方便的使用valgrind这个工具方便检测内存泄漏和内存错误. 安装很方便: debian(如ubuntu) sudo apt-get install valgri ...

  6. 段错误、内存泄漏、内存溢出、堆溢出、栈溢出

    参考:内存泄漏.内存溢出.段错误.堆溢出.栈溢出 作者:焦木白 发布时间:2019-10-22 网址:https://blog.csdn.net/jiaomubai/article/details/1 ...

  7. 单例模式引发的内存泄漏:_资源泄漏:救援的命令模式

    单例模式引发的内存泄漏: 多年来, 使用Plumbr进行性能监控时,我遇到了数百个资源泄漏引起的性能问题. 在这篇文章中,我想描述一种最简单的方法来清理资源并避免该问题. 首先,我以电影播放器​​应用 ...

  8. valgrind 内存泄漏_应用 AddressSanitizer 发现程序内存错误

    应用 AddressSanitizer 发现程序内存错误 作为 C/ C++ 工程师,在开发过程中会遇到各类问题,最常见便是内存使用问题,比如,越界,泄漏.过去常用的工具是 Valgrind,但使用 ...

  9. Release编译模式下,事件是否会引起内存泄漏问题初步研究

    题记:不常发生的事件内存泄漏现象 想必有些朋友也常常使用事件,但是很少解除事件挂钩,程序也没有听说过内存泄漏之类的问题.幸运的是,在某些情况下,的确不会出问题,很多年前做的项目就跑得好好的,包括我也是 ...

最新文章

  1. 渥太华大学计算机硕士课程,渥太华大学计算机工程专业解析
  2. python中表示红色的表达式_python-SymPy中表达式的抽象表示
  3. python怎么知道用哪个库使用-dir、help 查看python 库 对应的方法 和使用
  4. c++Builder XE6 MD5 加密算法 BASE64 URL 编码
  5. SAP Cloud for Customer前台发送到后台的HTTP请求,遇到错误该怎么分析
  6. python中括号的作用_Python3--中括号[]与冒号:在列表中的作用
  7. 第二章--电商设计表
  8. linux 改变 asm磁盘组 权限,DBCA时出现ASM磁盘组权限问题ORA-27303
  9. 201671010139 2016-2017-2 JAVA 和C语言的语法区别
  10. 解决Eclipse Pydev中import时报错:Unresolved import
  11. Java、JVM、JRE、JDK等组件的理解
  12. 超神能力:云库局面分析
  13. linux离线安装flex,Flexbuilder 3在Linux下安装
  14. 洛谷P2122 还教室
  15. salt returner mysql_saltstack mysql returner
  16. 编译原理_P1003
  17. 关于matlab GUI重命名的问题。
  18. 研究生被导师嫌弃是种怎样的体验?写的太真实了...
  19. P1873 砍树 【二分】
  20. 那些百万年薪的算法工程师,都是经历了哪些九死一生?

热门文章

  1. Python fabric实践操作
  2. AIX系统卸载oracle
  3. CodeForces - 1245C Constanze's Machine(思维+找规律)
  4. 中石油训练赛 - Bee Problem(dfs+连通块)
  5. linux循环条件,shell脚本编写 之 条件选择,条件判断,循环语句
  6. python agg函数_Python Pandas Series.agg()用法及代码示例
  7. linux停止python程序_python – Linux上的多处理进程终止失败
  8. 贪心算法-03哈夫曼编码问题
  9. win7下反汇编程序程序基址改变问题
  10. 阿里巴巴:全链路压测体系建设方案的思考与实践